If you’re not giving your images an explicit width and height, you may be hurting your cumulative layout shift (CLS) score. Setting width and height on images is even more important now that Google plans to include Core Web Vitals in its ranking algorithm—and CLS is just one metric that Google looks at when auditing your site. But what do images have to do with layout shifts, anyway, and how does giving them a width and height solve this problem?
Table of Contents
- Dimensionless Images Can Cause Layout Shifts
- Fixing Layout Shifts by Setting Width and Height on Images
- Fallback: Aspect Ratio Containers with Percentage Padding
- Summary
- Further Reading
Dimensionless Images Can Cause Layout Shifts
Chances are that you’re already using CSS like this on your site to create responsive images that scale with the device width:
img {
max-width: 100%;
width: 100%;
height: auto;
}
If so, great! But while this CSS gives you responsive widths and heights, it doesn’t ensure that the right amount of vertical space is reserved for your image before it loads in.
If you don’t give an image a width and height, it will initially collapse to a height of zero until it has loaded in and the browser is able to calculate the right height for it. If an image is in the viewport when the page loads in, then an initial height of zero means that any content after the image will initially be painted above where it’s actually supposed to go, like the second paragraph in this diagram:
Once the image finishes loading, it will push that content down and take its rightful place:
This is known as a layout shift. As its name implies, a layout shift is… well, a shift in layout. In other words, a layout shift occurs when elements jump around on a page. Common sources of layout shifts include:
- Flash of un-styled text (FOUT) due to
font-display: swap
and a poorly chosen fallback font. - Images without an explicit width and height. We’ll get to why this is a problem in a second.
- Dynamically or conditionally rendered content.
Tools like Lighthouse mainly measure unexpected layout shifts, which are not due to the user interacting with the page but rather factors that are beyond the user’s control, like images loading in. You can learn more about how cumulative layout shift is calculated on Web.dev.
Bottom line: Too many layout shifts can create a frustrating user experience, where content noticeably jumps around and users are left confused. Plus, layout shifts are visually unpleasant and can make your design look sloppy or poorly optimized.
In the following sections, we’ll specifically look at how images without width and height attributes can cause layout shifts. We’ll also discuss why setting a width and height solves that problem.
Fixing Layout Shifts by Setting Width and Height on Images
To prevent these kinds of layout shifts, we can give our images an explicit width and height. When we do that, certain browsers (like Chrome) define the image’s aspect ratio under the hood. This allows the browser to reserve the right amount of vertical space for your image before it loads in.
That’s the short answer, at least—but let’s also dig deeper into how this really works. Note that I’ve written about how to create aspect ratios in CSS in the past, but I’ll do a quick recap here.
What Is an Aspect Ratio?
An aspect ratio describes the relationship between an element’s width and height. Common aspect ratios include 16:9
, 4:3
, and 1:1
. For example, an aspect ratio of 1:1
tells us that the width and height of an element are always the same (i.e., it’s a square), whereas an aspect ratio of 16:9
tells us that the element has 16
units of width for every 9
units of height. Intuitively, this means that such an element is roughly twice as wide as it is tall.
You may not have considered how aspect ratios impact web performance, but they’re really important, especially now that Core Web Vitals is part of Google’s ranking algorithm. In short, aspect ratios allow us to size our images properly so that they don’t cause layout shifts once they finish loading. Let’s take a closer look at how this works.
A Glimpse Into the Future of CSS: aspect-ratio
As of Version 88, Chrome automatically applies a new CSS property—aptly named aspect-ratio
—to any element that has width
and height
attributes. For example, if your image is 1280x750
, then you’d set its width and height to be those values via HTML attributes:
<img src="path/to/img.png" alt="" width="1280" height="750" />
And Chrome would use those two numbers to compute the image’s aspect ratio, applying this CSS:
img {
aspect-ratio: auto 1280 / 750;
}
Here’s an example from my article that I linked to earlier, where an image is given width and height attributes of 500
and 300
, respectively; Chrome uses these attributes to compute the image’s aspect ratio and applies that CSS, which you can inspect in your dev tools:

Cool! But… How does setting an image’s aspect ratio prevent layout shifts? Plus, what if the image won’t actually load in at that particular width and height? Won’t this cause overflow or image distortion issues? Great questions! I’ll answer both of these below.
Reserving Vertical Space for Images with Aspect Ratios
On page load, your browser already knows the width to reserve for content based on your layout’s CSS and the device width. But what it doesn’t know ahead of time is how much vertical space it needs to reserve for your images since that can vary from one image to another.
This means that in the brief moment of loading in your content, if there are any images within the viewport, their initial height will be zero until the browser renders them. As previously mentioned, this can cause layout shifts, pushing content after an image down once it finishes loading in.
Aspect ratios solve this problem by reserving the right amount of height ahead of time for your content. Because an aspect ratio describes the relationship between an element’s width and height, and the browser already knows the width of the content area, this means it can calculate the precise height that the image will occupy once it finishes loading. Thus, the browser can reserve that amount of space ahead of time, preventing a layout shift from occurring!
Using the same diagrams as before, we would have an initial frame with two paragraphs and a collapsed image. The colored rectangle between the paragraphs represents the space that the browser has reserved for the image that has not yet loaded. It knows precisely how much space to reserve thanks to the image’s aspect ratio:
Once the image loads in, it simply occupies that placeholder space without shifting any of the surrounding content:
Lighthouse is happy, and so are your users!
Responsive Images with Fixed Aspect Ratios
Now, let’s address the other question: What if the final image isn’t going to actually render in at this width and height, even if those are its default dimensions? This is a very common question. And the good news is that you can still apply this CSS to size your images responsively:
img {
max-width: 100%;
width: 100%; /* scale with content width */
height: auto; /* compute a height that preserves the aspect ratio */
}
Naturally, the width
and height
here will override the default CSS applied by the width
and height
attributes that we set in our HTML:
<img src="path/to/img.png" alt="" width="1280" height="750" />
So why would we want to do this? Doesn’t this defeat the purpose of using HTML attributes in the first place? Nope!
Since aspect-ratio
is a CSS property computed and applied by the browser itself (only Chrome in this case), this means you can now set any responsive width and height on your images via CSS, and the aspect ratio will still be preserved. The aspect ratio will ensure that the right amount of height is always reserved for your images regardless of their final, responsive widths.
In other words, you can think of setting an image’s width and height as initializing its aspect ratio for the purposes of reserving the right amount of space so that it loads in cleanly. Once an image has loaded in, if you want to apply any CSS to size it differently, you can do so without changing its aspect ratio.
It’s a win-win: Your CLS score improves because you’re no longer shifting content after images once they load in, but you still get to size your images responsively so that they always assume the width of the content area and size their height automatically based on their aspect ratio.
That’s why the aspect-ratio
property is so exciting—once more browsers support it, it’ll allow us to easily create aspect ratios without resorting to hacks.
Wait a minute… What hacks?
There’s always a hack
Fallback: Aspect Ratio Containers with Percentage Padding
So Chrome (and, by extension, Chromium Edge) supports this new CSS property. Great! But what about others browsers, like Firefox or Safari? Unfortunately, as of this writing, they do not yet support aspect-ratio
. This means that if you set an explicit width and height on your images, browsers other than Chrome won’t automatically calculate an aspect ratio for you. Thus, you could still see some layout shifts as your images load in. Bummer.
Fortunately, we can use a fallback for browsers that don’t yet support aspect-ratio
: percentage padding and aspect ratio containers. In my post that I linked to earlier, I discuss how percentage padding works and how we can use this “hack” to create aspect ratio containers that work in all browsers. This is an age-old trick, so it’s not a hack in your typical sense—it works, and there are good reasons for why it works.
Here’s the important part: When you give an element a percentage value for padding, that percentage is defined relative to the width of the element’s parent. So, when you give an element a padding value like 5%
, that’s going to be 5%
of the width of the parent1. If your element takes up 100%
of its parent’s width, then percentage values for its padding are technically also defined relative to its own width.
1There are some nuances to how this works that I explore in my other article, especially with regard to terminology (like “parent” vs. “containing block”). I won’t discuss them here to avoid confusing beginners, but you’re more than welcome to read it if you’re interested!
As a reminder, we’re trying to create aspect ratio containers using just vanilla CSS and no fancy new properties. We just learned that we can use percentage padding to reference the width of an element’s parent. By extension, if we size the element so that it takes up 100% of its parent’s width, then we can really use percentage padding to reference that element’s own width.
We can follow these steps to create an aspect ratio container using the percentage padding trick:
- Zero-out the element’s height so that only padding influences it.
- Ensure that the element takes up 100% of its parent’s width.
- Set vertical padding on the element equal to the aspect ratio percentage.
What do I mean by “aspect ratio percentage” in that last step? Well, let’s suppose your image’s intrinsic dimensions are 1280x750
like before. This means that there are 750
units of height for every 1280
units of width. In other words, we can express the image’s height as a percentage of its width: 750/1280 = 0.5859375 = 58.6%
.
Knowing this, we can wrap the image in an aspect ratio container whose vertical padding is that percentage (in this case, 58.6%
). Either top or bottom padding (or some combination of the two) will work since all we need is for the total vertical padding to be equal to this percentage:
<div class="aspect-ratio-container" style="height: 0; padding-bottom: 58.6%">
<img src="path/to/img.png" alt="" width="1280" height="750" />
</div>
As we learned, this percentage is relative to the width of the aspect ratio container’s parent, like an article:
<article>
<div class="aspect-ratio-container" style="height: 0; padding-bottom: 58.6%">
<img src="path/to/img.png" alt="" width="1280" height="750" />
</div>
</article>
As long as the aspect ratio container takes up 100%
of its parent’s width—which block-level elements like <div>
s do by default—this will be the same as defining the aspect ratio container’s height as a percentage of its own width. And that’s the very definition of aspect ratio! The last step is to apply our responsive CSS from earlier to the nested image:
img {
max-width: 100%;
width: 100%;
height: auto;
}
If you’re using a static site generator that supports shortcodes/includes, you can create a reusable image component like the following that takes an optional width and height and applies an inline style on the image’s container to give it the right aspect ratio:
{% assign width = include.width %}
{% assign height = include.height %}
<picture
{%- if width and height -%}
style="height: 0; padding-bottom: {{ height | times: 1.0 | divided_by: width | times: 100 }}%;"
{%- endif -%}
>
<!-- maybe a source tag here for WebP/AVIF images -->
<img
src="{{ include.src }}"
alt="{{ include.alt }}"
{% if width %}width="{{ width }}"{% endif %}
{% if height %}height="{{ height }}"{% endif %}
/>
</picture>
And here’s the accompanying CSS:
picture {
display: block;
width: 100%;
}
picture img {
height: auto;
max-width: 100%;
width: 100%;
}
You’d use it like this:
{% include img.html src="path/to/img.png" alt="" width="1280" height="750" %}
And that would generate this output HTML:
<picture style="height: 0; padding-bottom: 58.59375%;">
<img
src="path/to/img.png"
alt=""
width="1280"
height="750"
/>
</picture>
Chrome will use the image’s width
and height
to apply the aspect-ratio
property in its CSS, whereas browsers like Firefox, Safari, and any others that don’t yet support this behavior will use the picture
tag as an aspect ratio container. Either way, the right amount of space will get reserved for your images, ensuring that they don’t shift any content as they load in.
You can verify this by rendering an example and deleting the nested <img>
tag via devtools. You’ll find that the <picture>
aspect ratio container won’t collapse its width and height—it will remain sized correctly, just as if you hadn’t deleted the image. Here’s an example from my site:
In this case, I used an aspect ratio container whose vertical padding is 100%
, meaning it’s a square. That’s because the width and height of my image are the same. And that’s all there is to it!
Summary
You need to put in a bit of work to render images properly on the web. While it sounds like a simple matter of just throwing in a valid source and setting an alt attribute for accessibility, you should also set a width and height—and maybe even create an aspect ratio container—so that your images don’t cause layout shifts once they finish loading in.
Liked this post? You may also want to check out my tutorial on optimizing images for the web.
Further Reading
While you’re at it, I also recommend giving these articles a read:
- Smashing Magazine: Setting Height And Width On Images Is Important Again
- Web.dev: Optimize Cumulative Layout Shift
- Web.dev: Displays images with incorrect aspect ratio
Attributions
The photo used in this post’s social media preview was taken by Rumman Amin (Unsplash).