inView

on in JavaScript
Last modified on

inView - JavaScript Lazy Loading
Photo by Mick Haupt on Unsplash

Loading Images Based on Screen Visibility

Lazy loading images is a technique that defers the loading of non-critical resources (such as images) until they are needed. This approach can significantly improve page load time and user experience, especially on pages with many images.

  • HTML Structure: Images are placed within <img> tags with a data-src attribute containing the URL of the image to be lazy-loaded.
  • JavaScript:
    • getViewportHeight(): A function to get the viewport height.
    • inView(): Determines if an element is in view based on its position relative to the viewport.
    • loadVisibleImages(): Loads images that are in or near the viewport. It checks if an image is within 500 pixels of the viewport and loads it if it is.
    • Event listeners for load and scroll events trigger the loadVisibleImages() function to load images when the page loads or is scrolled.

Note

The code uses a manual approach to lazy loading images. With the IntersectionObserver API, this manual method is obsolete, but it still might be used in various scenarios where IntersectionObserver is not supported or when fine-grained control over lazy loading behaviour is needed.

The following script is a tiny, tiny, vanilla JavaScript lazy loading solution, weighing in at just 258 bytes gzipped (445 bytes uncompressed). It loads images only when they are about to come into view, reducing initial page load time and bandwidth usage. Did I say tiny?

Note that the threshold is intentionally set to a lower value so you can see the loading event.

<img src="px.png" data-src="pawel-czerwinski-Y4rs8BpjCm4-unsplash.jpg" alt="" width="1920" height="1280">
/**
 * Get viewport height.
 * @returns {number} Viewport height.
 */
const getViewportHeight = () =>
    window.innerHeight || document.body.offsetHeight || 0;

/**
 * Check if element is in view.
 * @param {HTMLElement} elem - The element to check.
 * @param {number} nearThreshold - Threshold for considering an element as in view.
 * @returns {boolean} True if element is in view, false otherwise.
 */
const inView = (elem, nearThreshold = 0) => {
    const viewportHeight = getViewportHeight();
    const scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
    const elemTop = elem.offsetTop;
    const elemHeight = elem.offsetHeight;
    return scrollTop + viewportHeight + nearThreshold > elemTop + elemHeight;
};

/**
 * Load visible images.
 */
const loadVisibleImages = () => {
    const images = document.querySelectorAll("img[data-src]");
    images.forEach((img) => {
        if (img.offsetParent !== null && inView(img, 500)) {
            img.src = img.dataset.src;
            img.removeAttribute("data-src");
            img.addEventListener("load", () => img.removeAttribute("data-src"));
        }
    });
};

// Load visible images on page load and scroll
window.addEventListener("load", loadVisibleImages);
window.addEventListener("scroll", loadVisibleImages);

Related posts

Leave a Reply

Your email address will not be published. Required fields are marked *