Skip to content

Instantly share code, notes, and snippets.

@marcamos
Last active February 2, 2022 14:19
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save marcamos/48f7dd5d4c16c10508708950799d1b29 to your computer and use it in GitHub Desktop.
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.
// 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