Barebones CSS for Fluid Images
A few days back 
Primary goal: I want to test width: 100% versus max-width: 100% and how those interact with [width][height] and srcset attributes.
Now, my usual take was to pop some width: 100% CSS on that thing and call it a day. width: 100% CSS forces the image to fill up the width of the container. This overrides any [width] attribute you have set. This has the downside that the image can outgrow it’s own dimensions and can appear blurry.
Each case below uses a 200×200 image in both a 150px container (to shrink) and a 300px container (to grow).
width: 100%
Without [width][height]
 
   
  Using [width][height]
 
   
  The 100% in max-width refers to the container dimensions. Sometimes the [width] attribute will be smaller than this container, which means the image will not always be full width. Practically speaking, the image will never grow larger than its own internal or intrinsic dimensions.
Another way to think about this, the image width can range between 0 and [width], depending on the container size.
Editors note: the above section had a pretty glaring error and was corrected thanks to @CarolSaysThings, @HarryMoore2409, and @nhoizey! Sorry about that, y’all.
max-width: 100%
Without [width][height]
 
   
  Using [width][height]
 
   
  Let’s use srcset to add another eligible image width (now 200px and 400px) and see what happens. Spoiler alert: no surprises here! 🎉
srcset and width: 100%
Without [width][height]
 
   
  Using [width][height]
 
   
  Keeping our two eligible image widths in play (200px and 400px) let’s swap to use max-width: 100%.
srcset and max-width: 100%
Without [width][height]
 
   
  Using [width][height]
 
   
  This is where the rubber finally meets the road. For me, the above test was the most surprising part of the research—and why a deeper analysis of this perhaps introductory topic was worthwhile (for me).
When I traditionally used width: 100% it bulldozed the [width] attribute. But a strict max-width: 100% now competes with the [width] attribute. One solution is to add width: auto to pair with our max-width: 100% CSS.
September 9, 2021 Update: This article has been amended to add one additional caveat about mixing height: auto and width: auto.
That looks like this:
srcset and max-width: 100%
Using [width][height] and width: auto ⚠️ incurs CLS costs
 
   
  When Eleventy Image generates markup for more than one size, the <img> element uses the lowest size/quality source. But this behavior has me thinking that when srcset is in play it should use the largest dimensions for the [width] and [height] attributes. I wonder what y’all think about that? Practically, it would look like this:
srcset and max-width: 100%
Using [width="400"][height="400"]
 
   
  This makes max-width: 100% a bit more predictable, as the rendered size now matches the behavior when [width][height] are not included or when width: auto was left off. The maximum width now correctly matches the intrinsic width of the largest image in our srcset list.
February 24, 2021 Update: Eleventy Image v0.8.0 was released with the above [width][height] attribute optimization.
Again—practically I would recommend to pair max-width: 100% with width: auto to fix this in the easiest way but this might help avoid some confusion for some folks that aren’t aware of this.
September 9, 2021 Update: This article has been amended to add one caveat about mixing height: auto and width: auto.
Conclusions (aka TL;DR)
- All of these approaches operate the same when the container is smaller than the image.
- Using width: 100%can give you some blurry images if you’re not careful with your container sizes (without Content Layout Shift penalties).
- 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]! Use the largest[width]and[height]attributes to fix this.
- ⚠️ Do not use width: autopaired withheight: autoas this can incur Content Layout Shift penalties.
- But perhaps esoterically I’m walking away with this remaining question: when you have multiple image sizes listed in a srcsetlist, which dimensions do you use for the[width]and[height]attributes? I kinda want to use the largest one—any obvious downsides to that?
February 24, 2021 Update: Eleventy Image v0.8.0 was released to use the largest size for the [width][height] attributes.
Copy and Paste
Writing this blog post has swayed me to part from my width: 100% ways! I think this is what my boilerplate will be moving forward:
img {
  max-width: 100%;
}
img[width][height] {
  height: auto; /* Preserve aspect ratio */
}
/* Let SVG scale without boundaries */
img[src$=".svg"] {
  width: 100%;
  height: auto;
  max-width: none;
}February 24, 2021 Update: Chris Coyier posted a great follow up to this post on CSS Tricks with some super valuable extra information about how srcset affects rendered image dimensions.
Content Layout Shift Addendum
September 9, 2021 Update: Prior versions of this blog post recommended img[width] { width: auto; } to solve the problem of images rendering too small when the width and height attributes were smaller than the maximum intrinsic size supplied via the srcset attribute. The best fix here is to use the largest dimensions for your width and height attributes (even if you use a lower quality version for the src).
Additionally, 
width: auto in this way conflicts with the default styles for aspect-ratio and incurs Content Layout Shift penalties.
I tested and confirmed this to be true when you pair width: auto and height: auto together. You can view the tests on Codepen:
- ✅ <img>with{ max-width: 100% }no CLS penalties
- ✅ <img>with{ max-width: 100%; width: auto }no CLS penalties
- ✅ <img>with{ max-width: 100%; height: auto }no CLS penalties
- ❌ <img>with{ max-width: 100%; width: auto; height: auto }console logs CLS penalties.
- ✅ <img>with{ width: 100%; height: auto }no CLS penalties



40 Comments
MWDelaney
I am so lazy. I figure whatever CSS framework I'm using has solved this for me. I'm turning in my developer card.
Zach Leatherman
I was basically this same thing until about 2 days ago 😅 But I wrote it up so you can just read it and don’t have to write a bunch of tests to learn how it works! 🏆
Ivan Nikolić
It seems like I’ve been doing similar thig for quite some time, it’s just that it was more like trial and error thing! 😅 github.com/niksy/rational… Thanks for the writeup!
Cristovao Verstraeten
Mint post! I'm convinced ... I think 😅
Zach Leatherman
Mine is a tiny bit different but yes! zachleat.com/web/fluid-imag…
Carol 🌻
This is such a great explanation, thanks for writing it! 🙌🏼 I started my site rebuild layer by layer so I could learn things, and it’s definitely working 😅 I think 2 things surprised me from the off: that I needed CSS at all to get the picture element to be responsive; (+)
Carol 🌻
and that when you say max-width: 100% it relates to the image’s width but when you say width: 100% it relates to the image’s container’s width 🤔 The more you know 💫
Zach Leatherman
yeah I agree that’s weird 😅
Rob Dodson
Oh good write up! I think we inadvertently avoided the last issue because the value we use for the width attribute is always the width of the original image.
Zach Leatherman
oh interesting—so a bit of evidence that it’s okay to use larger width/height attributes?
Rob Dodson
Because we know our max column size when someone uploads an image to our cdn we give them back a snippet to use which has the width and height attributes prefilled and it has constrained them to our max column size.
Andy Bell
This is bloody excellent. Permission to update the modern CSS reset with your findings?
Rob Dodson
Yeah we combine it with srcset and on smaller screens it seems to download the correct smaller image
Rob Dodson
Btw Jen Simmons has a really good video on this that I found super helpful. youtu.be/4-d_SoCHeWE
Zach Leatherman
Of course! Your CSS reset is incredible, btw—well maintained!
Rob Dodson
Maybe also worth mentioning that we inline our css so the column width and img max-width styles are in place very early.
Zach Leatherman
Awesome, thanks!
Ivan Nikolić
Yes, I was refering to that, basically max-width and height combo! Your solution seems like more explicit and more resilient implementation 😄
Andy Bell
[blushes] It’s actually 3 squirrels stood on top of each other, in a long coat.
Zach Leatherman
@ericwbailey told me “the marvel is not that the bear dances well, but that the bear dances at all”
Eric Bailey
my_career.txt
Andy Bell
same tbh
Senthil P
Great post. In your demo (SRCSET AND MAX-WIDTH: 100% & Using [width="400"][height="400"]) for the small container, I still see the 400px image rendered in the browser. We should see the 200px image, right? Link zachleat.com/web/fluid-imag…
Dohány Tamás
Aspect-ratio extension would be nice to have! ;)
Zach Leatherman
This is what I expect to see:
Senthil P
Correct. But a 400px image downloaded for a 150px container seems to be expensive, right?
Zach Leatherman
My hunch is that using these test cases to analyze which image is selected in srcset might not be the best thing—I’d need to learn more about how the browser coalesces multiple requests of differing sizes. Note that the URLs for the images are the same on the left/right
Harry Moore
You say “The 100% in max-width refers to the image’s dimensions”, is that true? I thought % in CSS was based on the parent element size
Nicolas Hoizey
Currently reading your article, I'm really surprised by "The 100% in max-width refers to the image’s dimensions". IMHO, these 100% refer to the container width.
Nicolas Hoizey
You’re welcome! 👍
Demon Newman
I never thought of tagging styles to whether the height/width attribute is set! Very cool. Do you have thoughts on lighthouse yelling about missing width attributes though? Most of our images are sized with css and also have sizes attribute set so... do I ignore that?
Zach Leatherman
Yeah definitely add them, they’re an important performance optimization to establish the image’s aspect ratio to prevent layout shift!
Demon Newman
So if the image is fluid and 50% width.. do I put the intrinsic width (which I do not know) or what? Typically width is for display so this guideline deeply messes with me (and also changes image[width] bit in your snippet)
Malte Ubl
I wonder if there is ever a good reason to use width: auto? Could this be a warning in lighthouse?
Zach Leatherman
I mean, it does solve the [width][height] versus [srcset] conflict issue. See <img width="200"> in this 300px container with a srcset that has a 400w source in it (it should fit to the container, imo). But mostly I encourage folks to width/height to match your larg… Truncated
Malte Ubl
So people are using srcset with different aspect-ratio images? Agreed on largest intrinsic size being the right choice!
Zach Leatherman
(all that to say, I’d be a fan of a warning)
Zach Leatherman
oh, I wouldn’t think so—no. I only meant that solving that problem with `width: auto` instead of changing your attributes has non-obvious CLS consequences (imo)
Malte Ubl
Makes sense.
Radu
🥳 Thank you for that article, I did the same tests over and over again and never occurred to me to save the learning to get back to them. Now the theme song from Captain Planet comes to mind - "With out powers combined" the www ... is not that hard 😜