Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimization Detective: Implement lazy-loading of background images #1035

Closed
westonruter opened this issue Mar 7, 2024 · 10 comments · Fixed by #1708
Closed

Optimization Detective: Implement lazy-loading of background images #1035

westonruter opened this issue Mar 7, 2024 · 10 comments · Fixed by #1708
Assignees
Labels
Needs Dev Anything that requires development (e.g. a pull request) [Plugin] Optimization Detective Issues for the Optimization Detective plugin [Type] Enhancement A suggestion for improvement of an existing feature

Comments

@westonruter
Copy link
Member

westonruter commented Mar 7, 2024

Feature Description

At the WordCamp Asia Contributor Day, @shilo-ey shared a very interesting thing that Elementor is doing to optimize the loading of background images by lazy-loading them. Background images cannot be lazy-loaded using loading=lazy like regular images can since they are CSS and not img elements. So Elementor is using a clever approach to force all background images to be hidden after the first N with a style rule. Then it uses IntersectionObserver to remove the style rule once scrolling.

https://github.com/elementor/elementor/blob/498d48e8fed6cb8db2b0b3d3835cf1e44efbcbb8/modules/lazyload/module.php#L37-L97

This could be done with Optimization Detective as well, but in a more accurate way since it wouldn't have to assume to not lazy-load the first N images and it can instead use the elements in the URL metrics to know which background images are actually in the initial viewport, and only exclude them from lazy-loading.

See also WordPress/gutenberg#59113

When JavaScript is turned off, the lazy-loading of the background image should ideally be disabled. This can be achieved by wrapping the CSS rules to disable the background images outside the initial viewport with the scripting media query:

@media (scripting: enabled) {
   /*...*/
}
@westonruter westonruter added [Type] Enhancement A suggestion for improvement of an existing feature [Focus] Images [Plugin] Optimization Detective Issues for the Optimization Detective plugin labels Mar 7, 2024
@westonruter
Copy link
Member Author

westonruter commented Mar 25, 2024

See also this implementation that @erikyo just shared (see Slack thread): https://gist.github.com/erikyo/8e38a9bdeddfc3fea315399c0107ff09

Nevertheless, we need to be careful not to lazy-load a background image that is in the initial viewport.

@erikyo
Copy link

erikyo commented Apr 5, 2024

I'd like to provide an update to this thread since my exploration has progressed significantly since that initial gist!

My aim was to:

  • Implement lazy loading for backgrounds, videos, and all other elements requiring lazy loading within the page.
  • Achieve this without the need for any custom or special markup. Hence, approaches such as using CSS backgrounds or data-lazy attributes are not considered viable solutions.
  • Detect the position of elements within the viewport and prevent lazy loading on those items.

You can find the repository here along with the IIFE script (just in case you'd like to test it with your sources 😉).

If you'd like to give it a try, I've prepared some pages for testing with different scenarios:

In my tests, the pages are only slightly slower (by 100ms) compared to native lazyload. However, since native lazyload requires custom markup, auto-lazyload should provide an immediate reduction in page load time without the need to make any changes (and revert changes when you no longer want to use this plugin), especially for platforms like WordPress where there are elements such as covers with backgrounds, videos without posters, etc. This immediate improvement in load time can be significant.

Feel free to explore and test these pages! Let me know if you have any questions or feedback.

@erikyo
Copy link

erikyo commented Apr 5, 2024

Another metric that i can provide to show how this plugin act on a real website, is the Wordpress.org homepage waterfall. I use the local override to overrideride the html file and inject the autolazyload script at the beginning of the body, the result is 11sec vs 17sec, not bad 🎉

Auto-Lazyload
load

Current Wordpress website performance
load2

@rcwd
Copy link

rcwd commented May 14, 2024

Hello, i tried your js class and it is working well.
I have found an issue with background images added via js, i have this scenario:

<div id="mybgimage">.....</div>

<style>
#mybgimage{
    background-image: url(myimage.jpg);
}

@media only screen and (min-width: 592px){
    background-image: url(myimage-2.jpg);
}

@media only screen and (min-width: 1280px){
    background-image: url(myimage-3.jpg);
}

@media only screen and (min-width: 1536px){
    background-image: url(myimage-4.jpg);
}
<style>

What happens? By checking the Chrome console, all 4 bg images are downloaded in network tab.
Is there a way to fix this?

Thanks

@erikyo
Copy link

erikyo commented May 14, 2024

@rcwd thank you for testing! can you please file an issue here? 👉 the autolazyload repo

@rcwd
Copy link

rcwd commented May 14, 2024

@erikyo thanks! Issue opened.

@rcwd
Copy link

rcwd commented May 14, 2024

Hello again @erikyo, is there a way to exclude some images to be lazyloaded?

@erikyo
Copy link

erikyo commented May 14, 2024

@rcwd please refer to my GH repository, don't post here because unrelated

short answer: at the moment no, but if you kindly can file a new issue I will try to solve it! 😇

@ShyamGadde
Copy link
Contributor

Hi, could this issue be assigned to me? I'd like to work on it. Thanks!

@westonruter
Copy link
Member Author

westonruter commented Nov 22, 2024

Note that this would need to be limited to background images which are defined inline via style attributes, at least to start.

Background images which are defined in external CSS files are more difficult to handle. I'm working on prioritizing the loading of such externally-defined background images in #1584, but it may not be feasible to lazy-load them. This is because the detection logic doesn't know up-front which elements have background images, so it doesn't know which to attach data-od-xpath attributes for. For the LCP element with a background image at least, we might be able to figure out which element detected client-side corresponds with a tag when iterating over the document during optimization through some heuristics, especially if the element has an ID.

In any case, I expect that most non-inline background images are going to be used in the page header and so won't need to be lazy-loaded anyway.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs Dev Anything that requires development (e.g. a pull request) [Plugin] Optimization Detective Issues for the Optimization Detective plugin [Type] Enhancement A suggestion for improvement of an existing feature
Projects
Status: Done 😃
Development

Successfully merging a pull request may close this issue.

5 participants