Barebones CSS for Fluid Images

Avatar of Chris Coyier
Chris Coyier on

Grow sales with Customer Journey Smarts Mailchimp tracking pixel

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 with srcset—it may cap smaller than you want when using [width]! Pair with width: 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;

Direct Link →