Search code examples
htmlcssimageintrinsic-content-size

How to keep an image size intrinsic, before it is loaded, so layout is stable?


I had always thought you could specify an <img/>'s width and height attributes so the browser knows its physical dimensions without having to download (at least the header) first. But apparently the attributes are treated as CSS properties - and are thus overridden when you try to do something like width: 50%; height: auto. Then, until the image is downloaded, the computed height remains 0.
Is there a way to explicitly set the image's physical dimensions (effectively its aspect ratio) via HTML/CSS?

(...and avoid "flashes of unknown aspect ratio" / lots of nervous re-layouting when using Masonry - which you could perhaps work around, but I'm more interested in the basic problem. Even if i'm struggling with asking succinctly about it :)


Solution

  • Updating for 2021, we now have a widely supported standards-compliant way to do this is with the CSS aspect-ratio property.

    You can simply use the height and width like so:

    .myimage {
      width: 50%;
      height: auto;
      aspect-ratio: 1280 / 720;
    }
    

    This will first calculate the width as 50% of the parent element, then, with the height set to auto (it's best to explicitly set it to auto in case something else changes the height for maintainability), it will use the value in aspect-ratio to calculate the height it should reserve.

    This does affect the image element even after the image has been loaded though. Meaning if the aspect-ratio property doesn't match the image's actual aspect ratio, the image will be stretched to fit. You can prevent this by prepending the "auto" value.

    aspect-ratio: auto 1280 / 720;
    

    With that, it will use the defined aspect ratio before the image is loaded and the actual aspect ratio is known, then fall back to auto once the browser knows the intrinsic aspect ratio.

    This is not supported by non-standard browsers like Internet Explorer and Safari, so if you want to make this work in those purely with CSS, you'll need to continue using the first workaround in kubi's answer (as a side note, the 4th option is not and has never been on track to become part of the standard).

    However, this question would likely not even get asked if it were today (at least not by the same person) because there is now an HTML solution which is the old, pre-responsive web design HTML solution. Most modern browsers now use the image element's height and width attributes to calculate the aspect ratio, while CSS height and width override those values unless they are set to auto.

    Therefore...

    <img src='myimage.jpg' class='myimage' width='1280' height='720' />
    
    .myimage {
      width: 50%;
      height: auto;
    }
    

    This will now reserve the correct amount of vertical height, even in Safari. As of right now, there are still some browser-specific implementation notes to consider.

    In Chromium and Firefox, it is currently implemented using the CSS aspect-ratio property with "auto" prepending the calculated aspect ratio.

    aspect-ratio: auto attr(width) / attr(height);
    

    Since Safari doesn't support the aspect-ratio property yet as of my writing this, its implementation has a bit more nuance. As a result, it will not reserve space if there is not a valid image value in the src attribute, meaning if you are using old-fashioned JavaScript-based image lazy loading, you will need to include a fallback image.

    In any case, you should include height and width attributes on your image tags as much as possible. They actually do something now.