If you are dealing with Content Management System (CMS), you are likely to play with pages with large amount of images and embedded videos. To improve the performance of those pages, and save bandwidth for the readers, loading content asynchronously (also called “lazy loading”) is recommended.
It means the browsers will only load images and embedded videos in the visible area by default, then load the rest images and videos while users are scrolling down to them.
On our SSW Rules website, one of the pages’ initial loading size of images reduced from 4.8MB to 500KB after being applied “lazy loading” of images:
❌ Figure: Bad example - Load all images by default
✅ Figure: Good example - Do not load all images by default, only load them when they are visible while scrolling down the browsers
The page's initial loading size of JS scripts reduced from 2.3MB to 518KB after being applied “lazy loading” of embedded YouTube videos:
❌ Figure: Bad example – Load all embedded YouTube videos by default
✅ Figure: Good example - Do not load all embedded YouTube videos by default, only load them when they are visible while scrolling down the browsers
if (!("IntersectionObserver" in window)) {console.log("No Intersection");} else {console.log("Support intersection");}
Note: You can use a polyfill library to add IntersectionObserver support to older browsers.
<img alt="flight.jpg" src="https://ssw.com.au/images/flight.jpg" />
to
<img alt="flight.jpg" data-src="https://ssw.com.au/images/flight.jpg" />
function onIntersection(entries) {// Loop through the entriesentries.forEach((entry) => {// Are we in viewport?if (entry.intersectionRatio > 0) {// Stop watching and load the imageobserver.unobserve(entry.target);//console.log(entry);//console.log(entry.target);preloadImage(entry.target);}});}function preloadImage(target) {console.log(target);if (target.getAttribute("data-src")) {target.setAttribute("src", target.getAttribute("data-src"));}}// Get images of class lazyconst images = document.querySelectorAll(".sswRuleSummaryUCDiv img");const config = {// If image gets within 50px go get itrootMargin: "50px 0px",threshold: 0.01,};let observer = new IntersectionObserver(onIntersection, config);images.forEach((image) => {observer.observe(image);});
<iframewidth="853"height="480"src="https://www.youtube.com/embed/OhVYTOKCsWI"frameborder="0"></iframe>
To
<!-- (1) video wrapper in div instead of iframe --><divdata-iframewidth="853"data-iframeheight="480"data-iframecode="OhVYTOKCsWI"data-iframesrc="https://www.youtube.com/embed/OhVYTOKCsWI"frameborder="0"><!-- (2) the "play" button --><div class="play-button"></div></div>
let youtube = document.querySelectorAll("div[data-iframesrc]");for (var i = 0; i < youtube.length; i++) {let source ="https://img.youtube.com/vi/" +youtube[i].dataset.iframecode +"/sddefault.jpg";let image = new Image();image.src = source;image.addEventListener("load",(function () {youtube[i].appendChild(image);})(i));youtube[i].addEventListener("click", function () {let iframe = document.createElement("iframe");iframe.setAttribute("frameborder", "0");iframe.setAttribute("allowfullscreen", "");iframe.setAttribute("width", this.dataset.iframewidth);iframe.setAttribute("height", this.dataset.iframeheight);iframe.setAttribute("src",this.dataset.iframesrc + "?rel=0&showinfo=0&autoplay=1");this.innerHTML = "";this.appendChild(iframe);});}
More details can be found at How to “Lazy Load” Embedded YouTube Videos.