Last active
February 2, 2022 14:19
-
-
Save marcamos/48f7dd5d4c16c10508708950799d1b29 to your computer and use it in GitHub Desktop.
Lazy-loading polyfill; it covers the various ways you can use an <img> element, <picture> elements, and CSS background images … but it gets out of the way if the environment natively supports lazy-loading.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Use #1: <img> element using src and srcset: | |
// <img data-lazy-srcset="/path/to/image-2x.jpg 2x" | |
// data-lazy-src="/path/to/image-1x.jpg" | |
// alt="TODO" width="TODO" height="TODO" loading="lazy" /> | |
// | |
// Use #2: <img> element using src, srcset, and sizes: | |
// <img data-lazy-srcset="your srcset list here" | |
// data-lazy-src="/path/to/image.jpg" | |
// sizes="your sizes list here" | |
// alt="TODO" width="TODO" height="TODO" loading="lazy" /> | |
// | |
// Use #3: <picture> element: | |
// <picture> | |
// <source data-lazy-srcset="/path/to/image-2.jpg condition"> | |
// <source data-lazy-srcset="/path/to/image-3.jpg condition"> | |
// <img data-lazy-src="/path/to/image-1.jpg" | |
// alt="TODO" width="TODO" height="TODO" loading="lazy"> | |
// </picture> | |
// | |
// Use #4: CSS background images: | |
// 1. Add this selector to your CSS: | |
// .lazy-bg { | |
// background-image: none !important; | |
// } | |
// 2. Add a class of .lazy-bg to element(s) | |
export default function lazyLoadImages() { | |
let lazyHtmlImages = document.querySelectorAll('[data-lazy-src], [data-lazy-srcset]') | |
let lazyCssImages = document.querySelectorAll('.lazy-bg') | |
let nativeSupport = false | |
// If the environment natively supports lazy loading | |
if ('loading' in HTMLImageElement.prototype) { | |
nativeSupport = true | |
// Immediately swap the <img>/<picture> elements' attribute(s) as needed | |
lazyHtmlImages.forEach(function(el) { | |
handleHtmlImg(el) | |
}) | |
} | |
// If the environment supports IntersectionObserver | |
if ('IntersectionObserver' in window) { | |
// Get an intersection observer ready | |
let observer = new IntersectionObserver(function(entries) { | |
entries.forEach(function(el) { | |
if (el.intersectionRatio > 0) { | |
handleHtmlImg(el.target) | |
handleCssImg(el.target) | |
observer.unobserve(el.target) | |
} | |
}) | |
}) | |
// If the environment does not natively support lazy loading | |
if (!nativeSupport) { | |
// Use the intersection observer on the <img>/<picture> elements | |
lazyHtmlImages.forEach(function(el) { | |
observer.observe(el) | |
}) | |
} | |
// Use the intersection observer on the css background images | |
lazyCssImages.forEach(function(el) { | |
observer.observe(el) | |
}) | |
} | |
// If the environment does not support IntersectionObserver, we're not going | |
// to lazy-load anything, so we immediately update everything | |
else { | |
lazyHtmlImages.forEach(function(el) { | |
handleHtmlImg(el) | |
}) | |
lazyCssImages.forEach(function(el) { | |
handleCssImg(el) | |
}) | |
} | |
// Handle the <img>/<picture> element's attribute(s) swap | |
function handleHtmlImg(el) { | |
if (el.dataset.lazySrc) { | |
el.src = el.dataset.lazySrc | |
delete el.dataset.lazySrc | |
} | |
if (el.dataset.lazySrcset) { | |
el.srcset = el.dataset.lazySrcset | |
delete el.dataset.lazySrcset | |
} | |
} | |
// Handle the css background image element's class removal | |
function handleCssImg(el) { | |
if (el.classList.contains('lazy-bg')) { | |
el.classList.remove('lazy-bg') | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment