shinsenter / defer.js

🥇 A lightweight JavaScript library that helps you lazy load (almost) anything. Defer.js is dependency-free, highly efficient, and optimized for Web Vitals.
https://shinsenter.github.io/defer.js/
MIT License
277 stars 45 forks source link

feature_request(option): load scripts/styles/fonts once #128

Closed Kristinita closed 6 months ago

Kristinita commented 6 months ago

1. Summary

If a site developer uses Defer.js to lazily load scripts/styles/fonts when a site visitor scrolls the page to specific elements, it would be nice to have the option to load the script/style/font solely once. For example, the once option.

It might be a good idea to make once: true the default. For my site, I don’t know of any cases where I would have to use once: false.

2. MCVE

2.1. Purpose

For example, I want the Scada font to load not immediately when a site user opens a page, but when he scrolls the page to the first element that should be with this font — in the case of MCVE, this is the div element.

2.2. Code

Live demonstration on LiveCodes.

<script src="https://cdn.jsdelivr.net/npm/@shinsenter/defer.js/dist/defer.min.js"></script>
<div>Kira Goddess!</div>
<div>Kira Goddess!</div>
<div>Kira Goddess!</div>
<div>Kira Goddess!</div>
div
    font-family Scada, Arial, Helvetica, sans-serif
    margin-top 200rem
Defer.dom "div", 0, "KiraScadaFontLazyLoading", ->
    kiraScada = document.createElement("link")
    kiraScada.setAttribute "href", "https://fonts.googleapis.com/css2?family=Scada:ital,wght@1,700&amp;display=swap"
    kiraScada.setAttribute "rel", "stylesheet"
    document.querySelector("head").append kiraScada
    console.log("Scada font loaded!")

2.3. Steps to reproduce

  1. Open browser console
  2. Scroll the page from the beginning to the end.

2.4. Behavior

2.4.1. Desired

Defer.js loads the font 1 time when the first <div> element appears when scrolling the page. The font doesn’t load again when the user scrolls the page to other <div> elements.

<link href="https://fonts.googleapis.com/css2?family=Scada:ital,wght@1,700&amp;amp;display=swap" rel="stylesheet">
2.4.2. Current

Defer.js loads the font every time the user scrolls to any <div> element on the page. For the MCVE, Defer.js loaded the font 4 times.

Scada font load 4 times

Scada font loaded in console

<link href="https://fonts.googleapis.com/css2?family=Scada:ital,wght@1,700&amp;amp;display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Scada:ital,wght@1,700&amp;amp;display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Scada:ital,wght@1,700&amp;amp;display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Scada:ital,wght@1,700&amp;amp;display=swap" rel="stylesheet">

3. Reason for needing feature

To improve performance, might be nice when scripts/styles/fonts aren’t loaded immediately, but when the site user scrolls the page to a certain element. The documentation for Defer.dom() described solely cases where the selector is id. But a selector can be a tag or a class, and HTML markup can contain many of these tags or classes. It would be nice if Defer.js could be used for such cases.

4. Replies to possible counterarguments

4.1. “Just use ids instead of tags and classes”

For example, Defer.dom "#ExampleId"… instead of Defer.dom "div"….

  1. The site developer must add ids to the site markup specifically for Defer.js. This can be time-consuming.
  2. A site visitor can open a link with an anchor. For example:

    <div id="ExampleId">Kira Goddess!</div>
    
    <h2 id="ExampleHeader"></h2>
    
    <div>Kira Goddess!</div>

    The user can open https://example.site/ExamplePage.html#ExampleHeader and scroll the page down. In this case, the font that Defer.js loads when scrolling to #ExampleId will not load. It would be nice if Defer.js could load scripts/styles/fonts once when scrolling to any element from multiple elements, and not just to the top element in the HTML markup.

4.2. “Just use JavaScript”

  1. If the once: true option existed, I would use it in several cases on my site. It would be nice if adding once: true was enough, rather than adding JavaScript in every case.
  2. I searched on Google for queries like “javascript run function once”, but I didn’t find how I can get the desired behavior. If you think that the option isn’t needed, please show a working JavaScript example for my MCVE how I can get the desired behavior.

Thanks.

shinsenter commented 6 months ago

Hello @Kristinita

Thank you for your interest in my library and for suggesting ideas to improve it.

Regarding your issue, loading additional fonts through a callback function is completely unrelated to the existing functions of the library. Since the callback function is defined by you, my library simply runs it according to the intended purpose you want it to perform.

Therefore, I don't think it's necessary for me to add the requested feature. Instead, why don't we try a different approach to achieve what you want?

Here's an idea:

If you need to lazy-load the Scada font for some div elements, you could load it using the Defer.css method just once, and then use Defer.dom to reveal your div elements when the user scrolls to their position.

Defer.css "https://fonts.googleapis.com/css2?family=Scada:ital,wght@1,700&amp;display=swap", "scada-700", 0, ->
    console.log("Scada font loaded!")

Defer.dom "div", 0, "KiraScadaFontLazyLoading", ->
    console.log("DIV revealed!")

This preloading would also help the browser load and cache the font ahead of time, so it will be ready as soon as the divs are revealed (instead of when the user scrolls to that div and the font starts loading, which could cause a rendering delay on slow connections).

Another idea is, you could use a variable to check if the font has already loaded, and load it if it hasn't.

fontLoaded = false

Defer.dom "div", 0, "KiraScadaFontLazyLoading", ->
    if !fontLoaded
        kiraScada = document.createElement("link")
        kiraScada.setAttribute "href", "https://fonts.googleapis.com/css2?family=Scada:ital,wght@1,700&amp;display=swap"
        kiraScada.setAttribute "rel", "stylesheet"
        document.querySelector("head").append kiraScada
        console.log("Scada font loaded!")
        fontLoaded = true

Best regards