Video loading=lazy attribute support
What is the issue with the HTML Standard?
If the video element offered loading="lazy" support, that attribute could be used to determine how other desirable video features behave, such as when autoplay starts playing, and when its poster image and video file data are fetched.
For example, loading=lazy combined with the autoplay attribute could cause a video to delay its poster image loading, its data fetching (other than metadata perhaps?), and its autoplay behavior until the video element is in (near) the viewport. Per my understanding, lazy autoplay is currently doable with JavaScript and it'd be great to offer a declarative HTML alternative.
Could <video loading="lazy" ..></video> be one already-familiar way to offer a set of lazy behaviors for video?
Huge fan of this, as it becomes more standard like img.
Had this convo via Slack with @tunetheweb and others.
Seems like logic could make multiple things happen as you describe:
preload="none" loading="lazy" poster="/image.jpg"would do nothing until the user scrolls near, then would load the poster and begin downloading the video; withoutautoplaythe user would need to initiate playing.preload="none" loading="lazy" autoplay poster="/image.jpg"would do nothing until the user scrolls near, then would load the poster and begin downloading the video; once the video is downloaded, begin playing.preload="metadata" loading="lazy" autoplay poster="/image.jpg"would only download metadata nothing until the user scrolls near, then would load the poster and begin downloading the video; once the video is downloaded, begin playing.- etc.
It bugs me that JS is required to autoplay lazy loaded videos... :-/
/sub and +1
Went hunting for why video can't lazy load and found this. On my site nerdy.dev there is a lot of savings potential. I use preload="none" right now, which saves a lot already, but all the poster images still download, even the ones way at the bottom. Would like to save that bandwidth and not use JS for this type of optimization.
cc @whatwg/media
My previous comment about options: https://github.com/whatwg/html/issues/6636#issuecomment-1125404102
I suppose a reason to want lazy-loading for videos (over preload="none" and some way to opt in to lazy-loading for the poster image) is when you don't have a poster image. Or you want some video data to be loaded (when scrolled into view) so that playback starts sooner when requested.
@argyleink : The closest thing to ideal that I have found (I did not create this, but cannot find who I pilfered from) is something like this for above-the-fold videos with "posters"...
<section class="video-wrapper">
<picture>
<source srcset="poster-image-mobile.png" height="1080" width="1920" media="(max-width: 1023px)">
<source srcset="poster-image-desktop.png" height="1920" width="1080" media="(min-width: 1024px)">
<img src="" loading="eager" alt="Descriptive text">
</picture>
<video preload="auto" autoplay muted loop playsinline controlslist="nodownload">
<source src="video-mobile.mp4" height="1080" width="1920" type="video/mp4" media="(max-width: 1023px)">
<source src="video-desktop.mp4" height="1920" width="1080" type="video/mp4" media="(min-width: 1024px)">
</video>
</section>
And can then add:
<link rel="preload" fetchpriority="high" as="image" href="poster-image-mobile.png" media="(max-width: 1023px)">
<link rel="preload" fetchpriority="high" as="image" href="poster-image-desktop.png" media="(min-width: 1024px)">
And position the video over the picture with:
<style>
img, video {
max-width: 100%;
width: 100%;
height: auto;
}
.video-wrapper {
display: grid;
grid-template: "container";
place-items: center;
place-content: center;
}
.video-wrapper > picture,
.video-wrapper > video {
grid-area: container;
}
.video-wrapper img {
width: 100%;
height: auto;
object-fit: cover;
}
</style>
For below-the-fold:
- change the
imgloadingto"lazy", - change the
videopreloadto"none", - remove the
videoautoplayand - remove the
"preload"links.
Bit verbose, but gets the job done:
- Above-the-fold: Correct image preloads based on
media, so is visible fast, as video downloads, just starts playing over top. If the poster image is the first frame of the video, it looks like it is kind of "stuck', then just starts playing, but you see something soon. - Below-the-fold: Correct image lazy loads based on
media, so is visible when the user scrolls to it, the video downloads if the user click it, and just starts playing over top.
Massive kudos to whoever initially came up with this.
Could I fly an API proposal that (I believe) is both not too hard to implement and targets all use cases raised here (except poster, which is covered by https://github.com/whatwg/html/issues/6636)?
Tl;dr I’d like lazy loading to cover two scenarios: 1) delaying prefetch requests for videos that are outside of the viewport; 2) delaying playback for autoplaying muted videos (aka video “gifs”) that are outside of the viewport. (Both of these are something we had to build custom IntersectionObserver solutions for at Framer.)
I think this is reasonably solved with two new attributes:
loading="lazy": acts similarly to a trivial user-landIntersectionObserver, switching betweenpreload="none"and the specified value ofpreloadbased on whether the video is ~within the viewportautoplay="in-viewport": a new value for the existingautoplayattribute, indicating that the video must play only within the viewport
I feel these primitives combine really well and also allow covering other scenarios as well, such as eg a news article where a relevant video starts playing when you scroll to it.
I agree with @iamakulov and would also like to suggest that lazy-loading poster images would be good to include with this as well.
Are implementations/patches helpful at this stage or does the spec need to lead on behavior? Thanks.
For autoplay="in-viewport", I see https://github.com/whatwg/html/issues/2364 and https://github.com/whatwg/html/issues/9793
Are implementations/patches helpful at this stage or does the spec need to lead on behavior? Thanks.
Experimental implementations (e.g. behind a pref) are OK and could help with finding issues or move things forward. It also signals implementer interest.
It seems to me that autoplay would need to wait alongside loading=lazy anyway to avoid negating its effects (by needing to load the video too early in order to start playing it). Along those lines, it makes sense for autoplay to pend on the same timing as loading=lazy when it's present, I think. Is that a fair assumption?
(additional autoplay values could be useful in other cases I suppose, but it seems like autoplay should depend on loading=lazy when it's present)
Following up! My team at Squarespace has been exploring the possibility of contributing one or more browser patches, Web Platform Tests, and proposed edits to the HTML standard to help move this feature along. We think it'll bring nice performance benefits. We hope to contribute some or all of the above in the near future, assuming that's helpful.
Based on our work with these so far, I wanted to add a few questions relevant to the HTML standard portion:
- The HTML spec currently says that the video
autoplayattribute may cause a video to begin playing either immediately at page load or when a video intersects with/near the viewport (and is thus, visible). It doesn't recommend one or the other (which is fair enough) though we've noticed that both Chromium and Webkit seem to usually deferautoplayuntil an element intersects, and we think that behavior feels expected and nice. After working with videoloading=lazyhowever, we do think that the standard should probably recommend deferringautoplayin this manner more firmly when a video element has theloading=lazyattribute. Otherwise,autoplaymay introduce data fetching that could override the lazy loading behavior. Since this deferral behavior is not present in Firefox currently, the draft Firefox patch we’ve been exploring includes the autoplay deferral when loading=lazy is present on a video, and it seems to match our expectations from a user perspective. Would this make sense to mention in the standard? - As other comments above mention, when
loading=lazyis present on a video element, we think it makes sense to deferposterimage downloads in addition to a video's source data. Implementation-wise, this will mean that the preload scanner needs to avoid early-fetches ofposterimages based on this attribute’s value as well, when applicable. Do we agree thatpostershould be deferred along with video data when loading is lazy? - When the
loadingattribute is present and has alazyvalue, we think its behavior should take priority over anything specified in the preload attribute as well during page load. The preload attribute should still control what is preloaded whenever the video begins loading data in general (eg upon viewport intersection). Does this sound okay?
Thanks for the feedback on those.
Also, if we are able to send a PR to this repo suggesting edits to the standard to support his attribute for video, would that be welcome? Should any Web Platform Tests we contribute (as Pull Requests) be linked to this PR if we are able to make it?
Thanks!
@scottjehl :
- Point 1: Yeah, seems like this should be normalized, ideally via spec, and if Chromium and WebKit already do it that way, seems to make sense to use that, and hope for others to implement consistently.
- Point 2: Yes, seems like it makes sense to parallel poster download with video download, though for delayed loading, I would make a case that skipping the poster would be smarter, so it doesn't interfere/delay the actual video trying to download, but that's a "best practices" issue, not an implementation one... ;-)
- Point 3: Like the idea that "[t]he preload attribute should still control what is preloaded"; I think all that really needs to change is that the
autobehavior should now defer to theloadingattribute, if it is present, right?
I would love to be able to use preload="metadata" loading="lazy" and have the browser preload only the metadata, then load the video/poster only when nearing the viewport intersection, but in discussions with Scott, it sounds like this is not going to do what I would want, consistently across browsers, so maybe delaying the preload there also makes more sense... (Unless browser start actually reducing what they download with metadata... 😉)
That's my 2 bits...
There seems to be quite a lot of different states and conbinations to consider. I couldn't help myself but had to write it down.
Let's start with when a video should start playing (assuming browser's auto-play constraints are met):
- if
autoplayattribute specified with any string except "lazy": play video on page load autoplay="lazy": only start playing when in viewport- no
autoplayattribute (orautoplay="none"if we want to be consistent with below): video needs to be started manually by clicking it
Now, if the video is not already playing, we still have the choice of when to load the video:
preload="auto": preload video on page loadpreload="lazy": preload video when in viewportpreload="none": do not preload video
And finally, if the video is still not preloading, we now still have the choice of when to load the poster and metadata. So if we want to have this completely configurable, we need two new attributes, preloadposter and preloadmetadata, that each can be set to lazy or not. (Default should be whatever current implementations do.)
The above seems all compatible with the current standard, except for the existing preload="metadata". That would have to be carefully reasoned about what whould take precedence.
And of course there's the question whether we want this kind of configurability. But it seems that sooner or later someone will propose to add it either way, so might as well think through all cases from the beginning.