3

I have an img element that looks like:

<img src="header-900x600.jpg" class="header-image" alt="" width="900" height="600" style="background-color: rgb(4, 96, 247);">

With the css:

.header-image {
    display: block;
    max-width: 100%;
    max-height: 400px;
    width: auto;
    height: auto;
}

Now this is meant to force the image to resize to be max-height: 400px, or max-width: 100% whilst keeping its aspect ratio. Although when loading the image collapses into:

enter image description here

And after the image loaded, it pushes the text down:

enter image description here

I thought that since the image has the width and height inline, the browser would know it's aspect ratio already, and the image wouldn't be jumping around? Is there something I am missing?

All I want is the image element, before the image source has loaded, to be in the same aspect ratio as the image will be. Making the layout not jump around!

bitten
  • 2,463
  • 2
  • 25
  • 44

3 Answers3

4

All major browsers are now capable of doing exactly this in their current versions.

When you specify width and height attributes in HTML on the img tag and in CSS you set a width (percentage or fixed, also max-width is valid) and height to auto (or vice versa) the browser calculates the correct size and aspect ratio out of it, until the image is loaded. When the image is loaded, it uses the dimensions of the loaded image, so these should not differ from the attributes you set, otherwise you will get a layout shift again.

Note, however, that an invalid image or an image that cannot be loaded might be treated differently than a not yet loaded image. It is not guaranteed that width and height attributes of the img are considered. (This is especially important if you want to test the behavior, you cannot simply remove the value of the src attribute, this won't get you the same result as a not yet loaded image.)

Also note that there are still issues with responsive images (picture element and srcset attribute of img element) as described in the follwing link.

A great article with more detailed info and browser support can be found here: https://www.smashingmagazine.com/2020/03/setting-height-width-images-important-again/

Note: Simply providing width and height to your images can result in a way better result in the new Lighthouse CLS (Cumulative Layout Shift) measurement, see https://web.dev/cls/

Creepin
  • 482
  • 4
  • 20
  • This answer is helpful, but the different uses of `width` and `height` are a bit confusing. Can you make it clearer that you need to set `width` and `height` HTML attributes, and then in _CSS_ set one of `width` or `height` to auto? – talljosh Aug 24 '21 at 00:55
3

The browser doesn't know anything about the image until it is loaded. You can't set parameters of an element that doesn't exist. Instead, simply add the image into a container with full width, like so:

<div class="container">
   <img src="header-900x600.jpg" class="header-image">
</div>

.container {
    display: block;
    width: 100%;
}    

.header-image {
    display: block;
    max-width: 100%;
    max-height: 400px;
}

Also what Tarik says in his answer is correct, if you are declaring auto height and width then max-height and max-width are doing nothing.

Claire
  • 3,146
  • 6
  • 22
  • 37
  • 1
    Ah okay. But it seems weird if you tell the browser that the image is going to x height and y wide, why can't it work out the rest? I am playing around with your CSS and I am struggling not with images in portrait.. I will get back to you if I make any progress :p – bitten Aug 05 '19 at 20:37
  • 1
    Browsers now do this: https://www.smashingmagazine.com/2020/03/setting-height-width-images-important-again/ – Creepin Oct 07 '20 at 10:44
2

You set the width and height to auto. This means that the size will be set to the currently loaded image rather than anything to do with the max-height or max-width.

Note that this is probably a duplicate of CSS: Keep Aspect Ratio of an Element for Given Height

To be clear, when you set width and height to auto, you are overriding the other settings that you set and telling the browser to detect the size of the image. While the image is downloading, it cannot, so it behaves as you describe.

You could programmatically use javascript to set these properties after you detect that the image is done loading.

tarik
  • 312
  • 1
  • 9