Say you have an image you’re using in an <img>
that is 800×600 pixels. Will it actually display as 800px wide on your site? It’s very likely that it will not. We tend to put images into flexible container elements, and the image inside is set to width: 100%;
. So perhaps that image ends up as 721px wide, or 381px wide, or whatever. What doesn’t change is that image’s aspect ratio, lest you squish it awkwardly (ignoring the special use-case object-fit
scenario).
The main point is that we don’t know how much vertical space an image is going to occupy until that image loads. This is the cause of jank! Terrible jank! It’s everywhere and it’s awful.
Update! This actually happened. So all you have to do is put the correct natural width and height attributes on images and they will load without jank, even if CSS makes the image fluid with. So do it like: <img src="image.jpg" width="800" height="600">
There are ways to create aspect-ratio sized boxes in HTML/CSS today. None of the options are particularly elegant because they rely on the “hack” of setting a zero height and pushing the boxes height with padding. Wouldn’t it be nicer to have a platform feature to help us here? The first crack at fixing this problem that I know about is an intrinsicsize
attribute. Eric Portis wrote about how this works wonderfully in Jank-Free Image Loads.
We’d get this:
<img src="image.jpg" intrinsicsize="800x600" />
This is currently behind a flag in Chrome 71+, and it really does help solve this problem.
But…
The intrinsicsize
property is brand new. It will only help on sites where the developers know about it and take the care to implement it. And it’s tricky! Images tend to be sized arbitrarily, and the intrinsicsize
attribute will need to be custom on every image to be accurate and do its job. That is, if it makes it out of standards at all.
There is another possibility! Eric also talked about the aspect-ratio
property in CSS as a potential solution. It’s also still just a draft spec. You might say, but how is this helpful? It needs to be just as bespoke as intrinsicsize
does, meaning you’d have to do it as inline styles to be helpful. Maybe that’s not so bad if it solves a big problem, but inline styles are such a pain to override and it seems like the HTML attribute approach is more inline with the spirit of images. Think of how srcset
is a hint to browsers for what images are available to download, allowing the browser to pick the best one for the scenario. Telling the browser about the aspect-ratio
upfront is similarly useful.
I heard from Jen Simmons about an absolutely fantastic way to handle this: put a default aspect ratio into the UA stylesheet based on the elements existing width
and height
attributes. Like this:
img, video {
aspect-ratio: attr(width) / attr(height);
}
Let that soak in.
Now if you already have:
<img src="image.jpg" width="800" height="600" />
It automatically has the correct aspect ratio as the page loads. That’s awesome.
- It’s easy to understand.
- A ton of the internet already has these attributes sitting on their images.
- New developers will have no trouble understanding this, and old developers will be grateful there is little (if any) work to do here.
I like the idea of the CSS feature. But I like 100 times more the idea of putting it into the UAUA stylesheet is no small thing to consider — and I’m not qualified to understand all the implications of that — but it feels like a very awesome thing at first consideration.
Jen has a ticket open for people to voice their thoughts and links to the bug ticket where Firefox is going to test this out to see how it goes.
How do you combine the
height
attribute with responsive images ?If it has an inline height, I think you have only one option. “height: auto !important;”
I guess all this is to prevent re-flow when the images are loaded in.
I am all for new features, so give us both the new image “intrinsicsize” attribute on “img” element and the “aspect-ratio” property in CSS please and thank you.
However, I am not sure I understand why the “aspect-ratio” CSS property would only work as an inline style placed in the HTML.
Does the browser not paint the page after it reads the CSS and then applies those styles to the elements? My thinking is, couldn’t you just wrap each image in a “div” or “figure” and set an aspect-ratio property on that in an external stylesheet and then have the images fill its container with
object-fit: cover;
.So let’s say all our images are wrapped in a div that has a class of “gallery-image”, could I not just write the following in an external stylesheet:
…then the browser would just paint in a bunch of 16/9 aspect ratio boxes and fill them with the image contained within?
Obviously, additional layout code would be needed for a grid or row of images…but all this I think would work in an external CSS file.
I have also not been including “width” and “height” attributes in my “img” elements for years since responsive web design became a thing and our images largely were fluid in size.
Really hope the aspect-ratio CSS would come to pass. I’ve been using the %padding-bottom as a work-around for responsive aspect ratio for now.
btw: For an non english native speaker is the word “intrinsicsize” absoulutly horrible. Why not “ratio” or another word…
You could also use custom properties to add an aspect-ratio to your images without defining a fixed height attribute.
Example:
HTML:
img src=”https://via.placeholder.com/3/4″
style=” –image-width: 800px;” alt=””
CSS:
img{
width: var(–image-width);
height: calc(var(–image-width)*3/4);
}
formula: height = width * aspectratio (e.g. 16/9, 3/4, 8/5 etc.)
Codepen:
img {
max-width: 100%;
height: auto;
}
Doesn’t have to be complicated.
So before that image loads, how much vertical space should the browser reserve an arbitrary image?
It doesn’t have any idea, hence, jank.
But you’re right, it doesn’t have to be complicated, check out the article above.
You need that CSS and the width and height attributes in the img element. The latter seems annoying but you’re already doing that with intrinsicsize as well… But yeah, I can confirm that it indeed works (the max-width: 100% overrides the width and the height: auto relies on the img’s attributes to figure out the actual height to use).
Why don’t we just implement
<amp-img>
and use their built in tools to allow for this?said no one ever.
I have also wrapped each img in a div with aspect ratio as inline style.
:root {
--main-width: 60vw;
}
.gallery-image {
width: var(--main-width);
height: calc(var(--main-width) * var(--aspect-ratio));
}
.gallery-image img {
width: 100%;
height: auto;
}
Forked pen from https://css-tricks.com/the-complete-guide-to-lazy-loading-images/
There is actually no need for any encoding of the SVG string. This is valid:
src=”data:image/svg+xml,”
Great article and SUPER quick win at the end to implement. We should be setting width and height attributes on images anyway, so that’s cool. I’m a little confused though. Can you give an example of a use case for wanting to know the vertical space an image would take up?
Hey Kevin,
Say you click on a link to some documentation, and that link takes you directly to an anchor tag halfway down a page.
As images above your current position load, they will shift the content down the page.
Using the techiniques described in the article, the browser would be able to leave the correct amount of vertical space and prevent this shift.