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

kubi picture kubi · May 25, 2016 · Viewed 15.1k times · Source

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 :)

Answer

kubi picture kubi · Apr 26, 2019

So, as soon as we set height: auto by CSS, the browser ignores the intrinsic size set by width and height HTML attributes.

Possible workarounds and a possible solution for the future:

  1. Use the Intrinsic Ratio Box hack
    <div style="height: 0; padding-bottom: 42.857%; position: relative">
      <img style="position: absolute; left: 0; height: 0; width: 100%; height: 100%" … />
    </div>
    
  2. Using data URIs and JavaScript pre-load a placeholder with the same aspect ratio (beware of rounding errors!)
    <img src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQIAJQAlAAD/2wBDAFA3PEY8MlBGQUZaVVBfeMiCeG5uePWvuZHI////////////////////////////////////////////////////wAALCAAPACMBAREA/8QAFgABAQEAAAAAAAAAAAAAAAAAAAEE/8QAFBABAAAAAAAAAAAAAAAAAAAAAP/aAAgBAQAAPwDQgoICv//Z"
      onload="this.src='https://via.placeholder.com/3500x1500.jpg'"/>
    
    If we are using the "blurry placeholder" technique, the framework might already be there.
  3. Same as two, but use an SVG - easier to create on the fly, but no blurry placeholder "for free", obviously
    <img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'
      width='350px' height='150px'%3E%3C/svg%3E"
      onload="this.src='https://via.placeholder.com/3500x1500.jpg'"/>
    
  4. If & once intrinsicsize lands (WICG, github/Chrome) and gets adopted, there will be a Proper Way to do this:
    <img intrinsicsize="350x150" width="…
    

All of these have downsides, of course.
You can try 2 & 3 in this Pen - it would need more work & testing, I'll probably wait for 4, which I consider a fix for something that shouldn't need fixing. Stupid browsers :)