Zach takes a look at some fundamental HTML+CSS usage for fluid, responsive images. Most of it, I’d say, is what you’d expect, but things get weird when srcset
gets involved.
I poked my way through, and in addition to the weird thing Zach noted, wanted to add one more thing. Let’s start like this:
<img src="./img.jpg" alt="" />
With no other CSS involved, this renders at the “intrinsic size” of the image. Say the original image is 400px wide, it renders 400px wide.
We should be putting width
and height
attributes on images, because it allows the browser to make space for them even before they are downloaded (even when they are fluid, which is super cool). So:
<img src="./img.jpg" alt="" width="400" height="300" />
Also nothing terribly weird there. Even if we slap max-width: 100%
in the CSS, that’ll do what we want: preserving space, behave fluidly, and not growing bigger than it should.
But let’s hold off on the max-width: 100%
thing for a second. If we just use srcset
and set up multiple sources.
<img src="./img.jpg" alt=""
srcset="./img-200.jpg 200w, ./img-400.jpg 400w" />
BAM, we blow out the width of the thing.
That won’t render at 200px
or 400px
—it’ll actually render at 100vw
, believe it or not. I think that’s because that’s the default sizes
value. I normally think of the sizes
attribute as not information about anything to do with actual layout, but just information for the browser to choose a source. But that’s not true here. It really does effect layout (in all browsers I tested). Here’s proof:
See the little one below it where all I change is the sizes
.
Anyway that’s not what Zach honed in on, but it’s similar. Let’s put back the responsible thing and add in width
and height
attributes.
<img src="./img.jpg" alt="" width="200" height="137"
srcset="./img-200.jpg 200w, ./img-400.jpg 200w" />
No more blowout (with or without sizes
) but now we have a new weird problem. This is basically like saying max-width: 200px
. Even though we have sources that are wider than 200px, we’ve capped the width at 200px. Zach puts it like:
Using
max-width: 100%
constrains the image to the container, but be careful when you use this withsrcset
—it may cap smaller than you want when using[width]
! Pair withwidth: auto
to fix this.
Zach’s final snippet is this, which I think reigns in all the weirdness:
img {
max-width: 100%;
}
img[width] {
width: auto; /* Defer to max-width */
}
img[width][height] {
height: auto; /* Preserve aspect ratio */
}
/* Let SVG scale without boundaries */
img[src$=".svg"] {
width: 100%;
height: auto;
max-width: none;
}