Skip to content

Instantly share code, notes, and snippets.

@CSElliyas
Created August 31, 2019 07:03
Show Gist options
  • Select an option

  • Save CSElliyas/58e2f330ea2adc6cc2c6fc3bba5e1c7d to your computer and use it in GitHub Desktop.

Select an option

Save CSElliyas/58e2f330ea2adc6cc2c6fc3bba5e1c7d to your computer and use it in GitHub Desktop.
(function() {
"use strict";
var config = {
// If the image gets within 50px in the Y axis, start the download.
rootMargin: "50px 0px",
threshold: 0.01
};
var observer;
//If we're using a browser without the IntersectionObserver (IE11, Safari 11), skip the lazy part and just load the resources
if ("IntersectionObserver" in window) {observer = new IntersectionObserver(onIntersection, config);}
//If we're using a browser without requestAnimationFrame (IE9, Opera Mini), just run the passed function
var rAF;
if ("requestAnimationFrame" in window) rAF = window.requestAnimationFrame;
else rAF = function(func) { func(); };
var tempImg = "data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==";
/**
* Temporarily replace a expensive resource load with a cheap one
*/
function storeSourceForLater(lazyItem, tempData) {
//Store our ACTUAL source for later
lazyItem.setAttribute("data-lazy-src", lazyItem.getAttribute("src"));
//Set the item to point to a temporary replacement (like a data URI)
lazyItem.setAttribute("src", tempData);
//Now observe the item so that we can start loading when it gets close to the viewport
observer.observe(lazyItem);
}
/**
* Temporarily prevent expensive resource loading by inserting a <source> tag pointing to a cheap one (like a data URI)
*/
function jamSourceLoading(lazyItem, tempData) {
var newSource = document.createElement("source");
newSource.setAttribute("srcset", tempData);
newSource.setAttribute("data-lazy-remove", "true");
//adding this source tag at the start of the picture tag means the browser will load it first
lazyItem.insertBefore(newSource, lazyItem.firstChild);
var baseImage = lazyItem.getElementsByTagName("img")[0];
if (baseImage) {
//this is a picture tag, so we need to watch the image (as the picture tag is smaller than the image usually)
observer.observe(baseImage);
}
}
/**
* Set up the lazy items so that they won't try to load when we add them to the document, but will once the user is close to seeing them
*/
function prepareLazyContents(lazyArea) {
var lazyImgs = lazyArea.getElementsByTagName("img");
for(var i = lazyImgs.length; i--;){
storeSourceForLater(lazyImgs[i], tempImg);
}
var lazyPictures = lazyArea.getElementsByTagName("picture");
for(var i3 = lazyPictures.length; i3--;) {
jamSourceLoading(lazyPictures[i3], tempImg);
}
}
/**
* Put the source back where we found it - now that the element is attached to the document, it will load now
*/
function restoreSource(lazyItem) {
lazyItem.setAttribute("src", lazyItem.getAttribute("data-lazy-src"));
lazyItem.removeAttribute("data-lazy-src");
}
/**
* Remove the source tag preventing the loading of picture/audio/video
*/
function removeJammingSource(lazyItem) {
var jammingSource = lazyItem.querySelector("source[data-lazy-remove]");
if (jammingSource) lazyItem.removeChild(jammingSource);
}
/**
* Handle the intersection postback
*/
function onIntersection(entries, obsvr) {
entries.forEach(function(entry) {
if(entry.intersectionRatio === 0) return;
//if the item is now visible, load it and stop watching it
var lazyItem = entry.target;
obsvr.unobserve(lazyItem);
//Just in case the img is the decendent of a picture element, check for source tags
removeJammingSource(lazyItem.parentNode);
restoreSource(lazyItem);
});
}
/**
* Retrieve the elements from the 'lazy load' no script tags and prepare them for display
*/
function setUp() {
//Get all the noscript tags on the page
var lazyLoadAreas = document.getElementsByTagName("noscript");
for(var i = lazyLoadAreas.length; i--;) {
var noScriptTag = lazyLoadAreas[i];
//only process the ones marked for lazy loading
if (!noScriptTag.hasAttribute("data-lazy-load")) continue;
// The contents of a noscript tag are treated as text to JavaScript
var lazyAreaHtml = noScriptTag.textContent||noScriptTag.innerHTML;
// So we stick them in the innerHTML of a new div tag to 'load' them
var lazyArea = document.createElement("div");
lazyArea.innerHTML = lazyAreaHtml;
//Only delay loading if we can use the IntersectionObserver to check for visibility
if(!observer) {
noScriptTag.parentNode.replaceChild(lazyArea, noScriptTag);
} else {
prepareLazyContents(lazyArea);
noScriptTag.parentNode.replaceChild(lazyArea, noScriptTag);
}
}
}
//If the page has loaded already, run setup - if it hasn't, run as soon as it has.
//Use requestAnimationFrame as this will propably cause repaints
if (/comp|inter/.test(document.readyState)) {
rAF(setUp);
} else if ("addEventListener" in document) {
document.addEventListener("DOMContentLoaded",
function(){rAF(setUp);});
} else {
document.attachEvent("onreadystatechange", function() {
if (document.readyState=="complete") {
setUp();
}
});
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment