Add native loading=lazy support for video elements#2450
Add native loading=lazy support for video elements#2450adamsilverstein wants to merge 5 commits into
Conversation
Add loading="lazy" as a progressive enhancement for video elements that are below the fold, alongside the existing JavaScript-based lazy loading. For LCP and visible videos, remove any existing loading attribute to prevent unintended lazy loading. This leverages the new HTML spec support for loading="lazy" on video elements (whatwg/html#10376) while keeping the JS IntersectionObserver fallback for browsers that don't yet support it.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## trunk #2450 +/- ##
==========================================
+ Coverage 69.17% 69.34% +0.17%
==========================================
Files 90 90
Lines 8243 7752 -491
==========================================
- Hits 5702 5376 -326
+ Misses 2541 2376 -165
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
|
I verified this worked as expected on a test page in my local. Non LCP video tags get the lazy loading attribute: <figure class="wp-block-video"><video class="od-lazy-video" data-od-added-class data-od-added-data-original-preload data-od-added-loading data-od-added-preload data-od-xpath="/HTML/BODY/DIV[@id='page']/*[3][self::DIV]/*[1][self::DIV]/*[1][self::MAIN]/*[1][self::ARTICLE]/*[1][self::DIV]/*[12][self::FIGURE]/*[1][self::VIDEO]" data-original-preload="default" loading="lazy" preload="none" height="904" style="aspect-ratio: 1392 / 904;" width="1392" controls src="https://wpdev.localhost/wp-content/uploads/2026/04/inner-button-turns-to-save.mp4"></video></figure> |
Should this check for native support for video lazy-loading and short-circuit when this is the case? The logic in the JS can short-circuit if |
Actually, this is probably the better check: 'loading' in HTMLMediaElement.prototypeI just updated to Chrome 148 and confirm that this is |
Co-authored-by: Weston Ruter <[email protected]>
…g is supported When the browser supports `loading="lazy"` on video elements (detected via `'loading' in HTMLMediaElement.prototype`), restore the original preload, autoplay, and poster attributes immediately. The browser then defers the video load itself via the `loading="lazy"` attribute, avoiding the need for an IntersectionObserver-based fallback. Addresses review feedback on PR #2450.
|
Updated in e871d03 to short-circuit the IntersectionObserver when The three inline suggestions from your review are already applied in 771be4f. |
The test helper normalizes inline scripts by replacing them with a `/* const <varname> ... */` placeholder taken from the first declared identifier. After refactoring lazy-load-video.js to begin with `const restoreVideo`, the expected snapshots need to match.
Summary
Closes #2400.
loading="lazy"as a progressive enhancement for<video>elements that are below the fold (intersectionRatio = 0), alongside the existing JavaScript IntersectionObserver-based lazy loadingloadingattribute from LCP videos and visible videos to prevent unintended lazy loadingod-lazy-videoclass,data-original-*attributes,lazy-load-video.js) since browser support forloading="lazy"on video is still rolling outThis leverages the new HTML spec support for
loading="lazy"on video elements (whatwg/html#10376). In unsupported browsers, the attribute is simply ignored (zero cost). Audio tag support is deferred to a separate PR.Test plan
loading="lazy"alongside JS lazy loadingloading="lazy"has the attribute removedloading="lazy"has the attribute removedAI Usage
I used Claude code to write the code and tests for this PR which I reviewed. It should probably be manually tested as well, I have not done that yet. The PR is mostly test cases, the code change itself is minor.