This is a slightly different post to normal, normally I talk about things that are either already implemented in a browser or have just recently been added to the spec. Today I'll be looking at something that is still waiting to be merged into the spec.
I hope this will give you a better understanding of how the spec develops over time but also give you the confidence to suggest your own improvements. The whatwg team is very open to hearing new ideas.
W3 Bug report
Our story starts in 2012. Josh, from the BBC Web team, posted this bug to the w3 website.
The BBC updated their BBC News mobile website, recently. One of the ways they optimised it for mobile devices was by deferring loading images until after the page has loaded.
I haven't looked into how this is done in detail, but they used DIVs for placeholders in the positions where the images will go. For example:
<div class="delayed-image-load" data-src="http://static.bbci.co.uk/news/200/media/images/59388000/jpg/_59388680_59388679.jpg"></div>
After the page has loaded, the DIV is changed into an IMG element.
Clearly, this isn't very semantic, and wouldn't work at all if JavaScript is disabled. But they have a good reason for doing this, which is why I believe there is a need for a way of deferring the loading of images until after the page has been parsed. This could also be applied to other embedded content elements, like IFRAME and OBJECT.
The way I think this should be done is by using the DEFER attribute, which would work in the same way as it does in the SCRIPT element.
To break this down, they'd like to be able to have an <img>
tag with a defer
attribute that leads to the image not rendering until the site is ready
.
<img src="https://via.placeholder.com/150" defer />
This would lead to the images not loading until after first painting making the site appear to load quicker.
GitHub Issue
The conversation went stale after a couple of years but, in 2017, Josh brought it up again this time on GitHub.
Preventing downloading images or objects until they are visible in the viewport #2806
See PR #3752
Problem
Many websites are very image heavy, but not all of those images are going to be viewed by visitors. Especially on mobile devices where most visitors do not scroll down very much; it is mostly the content at the top of the page that is consumed. Most of the images further down the page will never be viewed, but they are downloaded anyway.
This is slowing down the overall page load time, unnecessarily increasing mobile data charges for some visitors and increasing the amount of data held in memory.
Example workaround
For years, the BBC News team have been using the following method to work around this problem. Primary images at the top of the page are included in the HTML document in the typical way using an img
element. However, any other images are loaded in lazily with a script. For those images, they are inidially included in the HTL document as a div
which acts as a placeholder. The div
is styled with CSS to have the same dimensions as the loaded image and has a grey background with a BBC logo on it.
<div class="js-delayed-image-load"
data-src="https://ichef.bbci.co.uk/news/304/cpsprodpb/26B1/production/_96750990_totenhosen_alamy976y.jpg"
data-width="976" data-height="549"
data-alt="Campino of the Toten Hosen"></div>
Eventually, a script will replace it with an img
element when it is visible in the viewport.
Doing this with a script is not ideal, because:
- If the visitor has scripts disabled, or the script fails to load, the images won't ever appear
- We don't know in advance the size of the visitor's viewport, so we have to arbitrarily determine which images to load in lazily. On a news article, vistors on small viewports will only initially see the News logo and an article's hero image, but larger viewports will initially be able to see many other images (e.g. in a sidebar). But we have to favour the lowest common denominator for the sake of mobile devices. This gives users with a large viewport a strange experience where the placeholders appear for a second when they load the page.
- We have to wait for the script to asyncronously download and execute before any placeholders can be replaced with images.
Solution
There needs to be a native method for authors to do this without using a script.
One solution to this is to have an attribute for declaring which images or objects should not be downloaded and decoded until they are visible in the viewport. For example, <img lazyload>
.*
Alternatively, a meta
element could be placed in the head
to globally set all images and objects to only download once they are visible in the viewport.
* An attribute with that name was proposed in the Resource Priorities spec a few years ago, but it didn't prevent the image from downloading - it just gave a hint to the browser about the ordering, which is probably not as useful in a HTTP/2 world.
Josh's idea had changed a little but the principle remained the same. Rather than a defer
attribute, a lazyload
attribute would be used the intention would be to only load images in the viewport.
<img src="https://via.placeholder.com/150" lazyload />
At the time of this post, the issue has 67 thumbs up, 11 hooray and 29 heart reactions. One of GitHub's huge benefit is the ability to easily show support for issues.
This time the conversation kept going and lead to a pull request!
GitHub the pull request
The pull request comes from a Google employee named Ben. People are adding bits and looking through the spec to make sure it all makes sense. As of 21 days ago, all the comments have been addressed and they're waiting for tests to be added.
Lazyload images #3752
This is a draft of spec changes to support a lazyload attribute in iframe and img elements.
Issue: #2806 Tests: https://chromium-review.googlesource.com/c/chromium/src/+/1417117 (wpt export)
/embedded-content.html ( diff ) /images.html ( diff ) /index.html ( diff ) /indices.html ( diff ) /media.html ( diff ) /rendering.html ( diff ) /urls-and-fetching.html ( diff )
The potential spec
Let's have a look at the description, we can't pop over to Mozilla to have a look this time as we're too early.
The attribute provides a hint to the user agent to aid in deciding whether to load an element immediately or to defer loading until the element will be viewable, according to the attribute's current state.
on
Indicates a strong preference to defer fetching the element's resource until it will be viewable.off
Indicates the element's resource must be fetched immediately, regardless of viewability.auto
Indicates that the user agent may determine the fetching strategy (the default).The attribute's
missing value default
andinvalid value default
are both theauto
state.
Here are some practical examples
<!--
this image will not be fetched until it
is in the viewport, meaning the page loads
faster and uses less data.
-->
<img src="https://via.placeholder.com/150" lazyload="on" />
<!--
this image will be fetched as soon as the
page opens, this is how website work currently
-->
<img src="https://via.placeholder.com/150" lazyload="off" />
<!--
this image will probably work the same as off
but there is space for interpretation
-->
<img src="https://via.placeholder.com/150" lazyload="auto" />
<!--
If the lazyload value is invalid or missing
the attribute will default auto
-->
<img src="https://via.placeholder.com/150" lazyload="bar" />
<img src="https://via.placeholder.com/150" />
Wrapping up
In my opinion, anything we can pass over to the browser leads to a better web. Having all images lazy load with no effort for the development team makes sense to me. Do you have any thoughts? Let me know down below.
If you have something you think the spec is missing head over to the issue and let them know. Updating the spec is a really delicate process the more help they get before any browsers have implemented it the better.
Thank you for reading, I know this was a little different to my other posts but I thought it was interesting all the same.
❤🦄🦄❤🦄❤🦄🦄❤
Top comments (5)
I'm really looking forward this new feature! Maybe something you could talk about would be the inert attribute 😉 it is still into draft but their is some great polyfills
That's a great idea!
I always interest to such discussion, can't wait for the new feature..:)
Wow this is awesome Andrew. Thinking we would have lazy loading "for free" once browser implement this...
BTW I'm really liking this series, thanks for doing it!
Thank you for saying that, it means a lot 🙂