6

I'm trying to optimize a page which consists of a grid of images with breakpoints that makes it use 1, 2, 3 or 4 columns.

The html looks like this:

<img srcset=" image-300x200.jpg 300w, image-original.jpg 600w" sizes=" (min-width: 1px) calc( 100vw * (0.94 * 1.000) * 1.00 ), (min-width: 480px) calc( 100vw * (0.94 * 0.905) * 0.50 ), (min-width: 768px) calc( 100vw * (0.94 * 0.850) * 0.33 ), (min-width: 981px) calc( 100vw * (0.94 * 0.835) * 0.25 ), 280px" alt="E-Books customer service for Dutch Libraries" width="400" height="284">

The calc() functions may look a bit complicated but I've tested them with various viewport widths and then verified the size of the image in the browser and the math checks out.

For completeness, here's what it does:

[viewport width] - [94% container width] - [column gutters] / [nr of columns]

But whatever I try, Chrome (almost, yay for consistency) always selects the big image even when the size of the img on screen is well below 300px. I checked this in the developer tools > inspector > properties > img > currentsrc as pointed out in this answer

Can anyone help me?

Community
  • 1
  • 1
REJH
  • 3,273
  • 5
  • 31
  • 56
  • 1
    This code by itself is not enough to replicate the problem. Can you provide a [mcve] that demostrates the issue? – Mr Lister Nov 29 '16 at 08:00
  • Sure i'll update the post as soon as i'm behind a computer – REJH Nov 29 '16 at 08:02
  • Heh. Building the example code kind of set me on the track of finding the answer. Posted it below. Thanks for asking :D – REJH Nov 29 '16 at 13:21

1 Answers1

3

I think I figured it out. it seems that the media queries don't work as I expected.

For example, with these rules:

sizes=" (min-width: 1px) ... (min-width: 480px) ... (min-width: 768px) ... "

one would assume that

  • Line #1 is true when screen > 1px wide
  • Line #2 is true when screen > 480px, overriding line #1
  • Line #3 is true when screen > 768px, overriding line #1 and #2

This is not how it works, at least not in practice. I think that the browser just looks for a rule that evaluates to true and calls it a day.

So it just goes:

  • Line #1 is true! Done! Applying the rule! Easy!

When I looked at my rules and the result with this logic in mind, it suddenly made sense that the browser insisted on using the biggest image because the calc() function I use for the first line is:

calc( 100vw * (0.94 * 1.0) * 1.0 ) - which is a complicated way of writing windowWidth * 0.94.

In other words, the browser assumes that the image is always 94% of the entire width of the window and doesn't apply any of the other calculations that take the breakpoints into account.

Anyway, changing the above rules to this:

sizes=" (min-width: 1px) and (max-width: 479px) ... (min-width: 480px) and (max-width: 767px) ... (min-width: 768px) and (max-width: 980px) ... "

makes sure that the rule only applies up to a certain point. Every time the next line evaluates as true, the other lines don't.

So this is what I went with in the end:

<img src="image-fallback.jpg" srcset=" image-300x200.jpg 300w, image-480x320.jpg 480w, image-600x400.jpg 600w, image-960x640.jpg 960w, image-1200x800.jpg 1200w" sizes=" (min-width: 1px) and (max-width: 479px) calc( 100vw * (0.94 * 1.000) * 1.00 ), (min-width: 480px) and (max-width: 767px) calc( 100vw * (0.94 * 0.905) * 0.50 ), (min-width: 768px) and (max-width: 980px) calc( 100vw * (0.94 * 0.850) * 0.33 ), (min-width: 981px) and (max-width: 1088px) calc( 100vw * (0.94 * 0.835) * 0.25 ), (min-width: 1089px) calc( 1089px * (0.94 * 0.835) * 0.25 ), 280px" />

And here's a working example of the above: Image srcset example (working)

Note: once the browser has loaded a larger image, it's reluctant to load smaller ones. That's what the 'force refresh' button is for.

Note #2: For debugging I added more source images compared to my original question. I thought it would be easier to keep it simple with two sizes but I think I would have never figured this out if I hadn't added a bunch. When I only had 2 images, I thought it always chose the biggest. That isn't true, it just never chose the image I expected ;)

REJH
  • 3,273
  • 5
  • 31
  • 56
  • oh btw you could probably write the rules in opposite order (from large to small) so you don't need to 'invalidate' other lines but.. I like to think mobile and work my way up, not the other way around. so this makes more sense in my workflow :) – REJH Nov 29 '16 at 13:32
  • 1
    For a mobile-first approach, you need only use `max-width` and then you can work your way up without bothering with `min-width` ;) – Mr Lister Nov 29 '16 at 15:00
  • Well yes and no. In css that would mean i'd have to redefine all the defaults over and over again. I usually do set defaults for small screens, then work my way up and only change the things i need to for larger screens :) – REJH Nov 29 '16 at 15:50