Created
October 11, 2019 09:29
-
-
Save lwkchan/906327dda598cb6b770ab4612f0126b0 to your computer and use it in GitHub Desktop.
Lazy loading images, with support for fallbacks for WebP and Intersection Observer
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
// 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