Skip to content

Instantly share code, notes, and snippets.

@lwkchan
Created October 11, 2019 09:29
Show Gist options
  • Save lwkchan/906327dda598cb6b770ab4612f0126b0 to your computer and use it in GitHub Desktop.
Save lwkchan/906327dda598cb6b770ab4612f0126b0 to your computer and use it in GitHub Desktop.
Lazy loading images, with support for fallbacks for WebP and Intersection Observer
// Script for lazy loading off screen images and background css images
// Also checks for webp support and adds that image if provided
// <img class="lazy-load" data-src="path-to-image.jpeg" /> // images with no webp support
// <div class="lazy-load-bg" data-src="path-to-image.jpeg" [data-src-webp="path-to-image.webp"]></div> // css background images. data-src-webp is optional
// <picture> // <picture> with webp support:
// <source class="lazy-load" data-srcset="path-to-img.webp" type="image/webp">
// <source class="lazy-load" data-srcset="path-to-img.jpg" type="image/jpeg">
// <img class="img-responsive small-legs lazy-load" data-src="path-to-image.jpg">
// </picture>
document.addEventListener("DOMContentLoaded", function () {
// Checks if browser supports lossy webp
// Image generation is asynchronous, so pass in cb to be executed after checking
function supportsWebP(callback) {
var lossyTestImage = "UklGRiIAAABXRUJQVlA4IBYAAAAwAQCdASoBAAEADsD+JaQAA3AAAAAA";
var img = new Image();
img.onload = function () {
var result = (img.width > 0) && (img.height > 0);
callback(result);
};
img.onerror = function () {
callback(false);
};
img.src = "data:image/webp;base64," + lossyTestImage;
}
var lazyloadCssBgImagesEls = document.querySelectorAll('div.lazy-load-bg');
if ("IntersectionObserver" in window) {
// Selects <img> and <source> tags
var lazyloadEls = document.querySelectorAll(".lazy-load");
var imageTagObserver = new IntersectionObserver(function (entries, observer) {
for (var i = 0; i < entries.length; i++) {
if (entries[i].isIntersecting) {
var imageEl = entries[i].target;
if (imageEl.tagName === 'IMG') {
imageEl.src = imageEl.dataset.src;
} else if (imageEl.tagName === 'SOURCE') {
imageEl.srcset = imageEl.dataset.srcset;
}
imageEl.classList.remove("lazy-load");
imageTagObserver.unobserve(imageEl);
}
}
});
for (var i = 0; i < lazyloadEls.length; i++) {
imageTagObserver.observe(lazyloadEls[i]);
};
supportsWebP(function (isSupportsWebp) {
var bgImageObserver = new IntersectionObserver(function (entries, observer) {
for (var i = 0; i < entries.length; i++) {
if (entries[i].isIntersecting) {
var div = entries[i].target;
// Makes sure that images we have not yet optimized still use the provided jpg
var imgUrl = isSupportsWebp && div.dataset.srcWebp ? div.dataset.srcWebp : div.dataset.src
div.setAttribute("style", "background-image: url(" + imgUrl + ");");
bgImageObserver.unobserve(div);
}
}
});
for (var i = 0; i < lazyloadCssBgImagesEls.length; i++) {
bgImageObserver.observe(lazyloadCssBgImagesEls[i]);
}
});
} else {
var lazyloadThrottleTimeout;
// selects <img> tags only (<source> and <picture> tags will default gracefully to the <img>)
var lazyloadImagesEls = document.querySelectorAll("img.lazy-load")
function lazyload() {
if (lazyloadThrottleTimeout) {
clearTimeout(lazyloadThrottleTimeout);
}
lazyloadThrottleTimeout = setTimeout(function () {
var scrollTop = window.pageYOffset;
for (var i = 0; i < lazyloadImagesEls.length; i++) {
var img = lazyloadImagesEls[i]
// if the distance of the element is less than the one viewport height from the viewport
// && only do this for img tags (as some lazy loading elements are <source> tags)
if (img.getBoundingClientRect().top < (window.innerHeight + scrollTop) && img.tagName === 'IMG') {
img.src = img.dataset.src;
img.classList.remove('lazy-load');
lazyloadImagesEls = document.querySelectorAll('img.lazy-load');
}
}
for (var i = 0; i < lazyloadCssBgImagesEls.length; i++) {
var div = lazyloadCssBgImagesEls[i];
if (div.getBoundingClientRect().top < (window.innerHeight + scrollTop)) {
div.setAttribute("style", "background-image: url(" + div.getAttribute('data-src') + ");");
}
}
if (lazyloadImagesEls.length === 0 && lazyloadCssBgImagesEls.length === 0) {
document.removeEventListener("scroll", lazyload);
window.removeEventListener("resize", lazyload);
window.removeEventListener("orientationChange", lazyload);
}
}, 20);
}
lazyload();
document.addEventListener("scroll", lazyload);
window.addEventListener("resize", lazyload);
window.addEventListener("orientationChange", lazyload);
}
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment