DEV Community

Cover image for Quick Tips: How to fix "Image elements do not have explicit width and height" in Page Speed Insights / Lighthouse
GrahamTheDev
GrahamTheDev

Posted on • Updated on

Quick Tips: How to fix "Image elements do not have explicit width and height" in Page Speed Insights / Lighthouse

If you have run your website through Google Lighthouse, Page Speed Insights, web.dev measure etc. you may have seen an action point of "Image elements do not have explicit width and height".

So how do we fix it?

The short Answer

All you need to do is add the images native width and height to the image.

You can do this with the width and height attributes, defining the sizes in pixels.

This then allows the browser calculate an aspect ratio (the ratio of the width to the height) and allocate enough space for the image before it loads.

So for an image that is 1600 pixels wide by 900 pixels tall:

<img width="1600" height="900" src="your-image.jpg">
Enter fullscreen mode Exit fullscreen mode

Long Answer

Lets take a typical example.

You have the following in your CSS file:

img{
    width: 100%;
    height: auto;
}
Enter fullscreen mode Exit fullscreen mode

This gives the browser enough information to calculate the images width as it can look at it's parent container width and calculate how wide the image should be.

height: auto however, is where the problem lies. It does not give the image an explicit height, but instead it is instructing the browser to make the image whatever height it thinks is appropriate based on the width of the image.

The problem with this is that the browser does not know the width or height of the original image when the HTML is parsed. It only finds out how large the image is when it starts downloading.

For this reason the following happens:

  • The browser downloads your HTML
  • it finds an image element and looks for any styles associated with it (which you should have inlined as part of your critical CSS)
  • it then renders the image element but does not know the height so gives it a 0 pixel height
  • it then requests the image and finds out it is 1600 pixels by 900 pixels
  • it then uses that information to create an aspect ratio of 16:9
  • it then revisits the image element it found earlier, looks at the calculated width (let's say it is 400 pixels on the screen) and applies the aspect ratio to calculate the height (400 / 16 * 9 = 300px).

This results in what is known as a Layout Shift. This is then added to the Cumulative Layout Shift (CLS) on the site.

As this is part of Google's web vitals and is very soon to be a metric that affects your search rankings, it is something you want to fix now.

How to fix it

There are a few ways to fix this, but here are two of the recommended ways to fix it, with the first being the preferred / best practice.

Option 1 - define the width and height of the image using the width and height attributes.

The first option is to define the width and height of the image using the height and width attributes.

<img width="1600" height="900" src="some-image.webp">
Enter fullscreen mode Exit fullscreen mode

Notice how the attributes do not include the units (pixels), they should be defined as integers.

In modern browsers this will then be used to calculate an aspect ratio for the image.

If you remember back to the previous section where we described the order of events in a browser, calculating the aspect ratio happened after the image element had been rendered as we didn't know the height of the image yet.

By applying a width and height attribute the browser can now calculate the aspect ratio before it renders the image element and can reserve enough space for the image once it downloads.

Using the width and height attributes is the recommended best practice to avoid layout shifts from images.

Top tip: One thing to note is that the browser will still obey and CSS sizing you apply.

So if you apply width:100% and height:auto as in the original CSS example it will still work correctly and obey your CSS rules. The only difference is that it can now calculate how big height: auto needs to be.

Bonus tip: Another interesting thing is that your height and width attributes only need to be the correct aspect ratio. So all of the following would result in the same behaviour as the ratio between the width and the height is the same:

  • <img width=1600 height=900>
  • <img width=800 height=450>
  • <img width=160 height=90 >

It is worth noting though that using as close as possible to the correct size is recommended just in case something goes wrong with your CSS.

Option 2 - "aspect ratio boxes"

This technique is also known as "the CSS padding hack".

What we do here is instead of defining the width and height on the image, we define the height of the image as a percentage of the width within our CSS file.

In order to achieve this we give our image a height of zero pixels (which is how it would render initially remember) and then use padding-top to allocate the correct amount of space in the document to avoid a layout shift.

HTML

<div class="image-div"></div>
Enter fullscreen mode Exit fullscreen mode

CSS

.image-div {
  overflow: hidden; /* not necessary if div is empty and other styles do not interfere */
  height: 0; /* not necessary if div is empty and other styles do not interfere */
  padding-top: 56.25%; /*aspect ratio of 16:9 at 100% width requires a 56.25% height*/
  background: url(/my-image.webp);
} 
Enter fullscreen mode Exit fullscreen mode

Or, if you don't need to support Internet Explorer you can use calc()

CSS using calc()

.image-div {
  overflow: hidden; /* not necessary if div is empty and other styles do not interfere */
  height: 0; /* not necessary if div is empty and other styles do not interfere */
  padding-top: calc(900 / 1600 * 100%); /*aspect ratio of 16:9, notice how we reverse the values as we are calculating the height from the width this time*/
  background: url(/my-image.webp);
} 
Enter fullscreen mode Exit fullscreen mode

This padding technique is explained in more detail in this article from CSS tricks

Why would you use this?

Obviously it is a bit of a hack and it requires you to use a background image on a div.

It is also not useful for anything other than decorative images as you cannot define an alt attribute for people who use assistive tech or have images switched off.

But it does have the advantage of keeping your HTML clean if you are a purist...but I don't think that is a good enough reason to use it!

What if you don't know the exact dimensions of the image?

Both the above techniques have one big flaw that you may have spotted.

When designing the page you have to know the width and height of the image to calculate the aspect ratio / add the appropriate width and height.

Obviously the solution is to handle this on the back end and use caching techniques to store the width and height attributes but this may not be possible.

If you are trying to fix this issue on an existing site that has thousands of images, or you cannot calculate the image width and height etc. you may have to make a minor compromise.

The fixed height container

Lets assume that all images on your site lie somewhere between a 1:1 aspect ratio and a 16:9 aspect ratio.

What we could do is add a container around all of our images that has a fixed height.

That way a browser is able to allocate space for the container on the page instead of the image.

The downside is you will end up with white space at the bottom of that container for images that are not the same aspect ratio.

The following fiddle demonstrates this technique:

I added background-color: #ccc to the container to show where the extra white space would be.

This technique is probably best used when images on a site are similar aspect ratios (some are 16:9, some are 16:10 for example) as the extra white space will not be as noticeable.

Conclusion

To wrap up, Cumulative Layout Shift needs to be minimised for a great user experience and soon to maintain your Search Engine Rankings.

The 3 techniques described above should hopefully let you fix this issue on your site if you haven't already done so.

I would recommend finding a way to automate adding a width and height attribute to your images for 99% of scenarios.

The only time this won't work is if you serve images with a different aspect ratio depending on the screen size (known as art direction) using the srcset attribute. In that scenario you will have to either use media queries and the padding hack or the fixed height container technique.

For the Algo!

My new sign off experiment!

If you enjoyed this article, give it a ❤, if you thought it was special give it a 🦄 and above all, don't forget:


Leave a comment for the algorithm! Especially if you have a scenario where you think the above techniques won't work 😁!

Top comments (5)

Collapse
 
grahamthedev profile image
GrahamTheDev

As a bonus tip for the future, one day we will be able to use aspect-ratio as a CSS property.

Unfortunately support for CSS aspect-ratio is only around 66% at the moment so it can't be used yet!

Collapse
 
afif profile image
Temani Afif

You don't really need to set height:0;overflow:hidden since your div is empty

Collapse
 
grahamthedev profile image
GrahamTheDev

Thanks as always bud, I added a note next to them for clarity.

Collapse
 
Sloan, the sloth mascot
Comment deleted
Collapse
 
grahamthedev profile image
GrahamTheDev • Edited

hehe, thanks bud, I hope this "for the algo" thing catches on and people start just randomly commenting "for the aglorithm" like you did - stole the idea from a YouTube channel called "slappers only" which is quite a funny channel if you ever get bored 😋

And yes, I don't think anything within this could possibly upset anyone!