Inhalte nur zu laden, wenn sie wirklich benötigt werden, sorgt nicht nur dafür, dass die Seite schneller das Dom-Ready erreicht, sondern erspart unter Umständen jede Menge Datentransfer, was nicht nur Google erfreut, sondern auch den Betrachter der Website.
Diese Implementierung bringt eine Filterung aller Bilder auf der Seite mit sich, die im data-src-Attribut einen Inhalt entalten, dieser Wert braucht nur in das src-Attribut verschoben werden, sobald das Bild im sichtbaren Bereich auftaucht und auch wirklich sichtbar sein soll.
Einzige Voraussetzung <img data-src = "..." loading = "lazy" />
Diese Implementierung unterstützt die native Variante loading="lazy" als img Attribute bei einem aktuellen Browser (ab Opera 64, Firefox 75, Chrome 76, Edge 79, Andoid Browser 80, Chrome for Android 80), aber auch den IntersectionObserver bei den etwas äteren (ab Opera 45, Firefox 55, Chrome 58, Edge 16, Safari 12.2, Andoid Browser 80, Chrome for Android 80, ...), sowie eine Variante über EventLisener für die ganz alten Browser wie z.B. den Internet Explorer , dadurch entsteht auch die breiteste Abdeckung für Lazy Loading. Zusätzlich wurde das Laden der Bilder vor dem Ausdrucken mit eingebaut, welches bisher von keinem Browser als Standard zur Verfügung gestellt wird.
viewport.js JavaScript (7,23 kByte) 18.12.2020 14:28
(function () {
'use strict' ;
function loadSrc(el) {
if (el.getAttribute('data-src' )) {
el.setAttribute('src' , el.getAttribute('data-src' ));
el.removeAttribute('data-src' );
}
if (el.getAttribute('data-srcset' )) {
el.setAttribute('srcset' , el.getAttribute('data-srcset' ));
el.removeAttribute('data-srcset' );
}
if (el.getAttribute('data-sizes' )) {
el.setAttribute('sizes' , el.getAttribute('data-sizes' ));
el.removeAttribute('data-sizes' );
}
return true ;
}
function preloadVideo(el) {
if (el.getAttribute('data-autoplay' )) {
el.setAttribute('preload' , 'auto' );
el.setAttribute('autoplay' , 'autoplay' );
el.autoplay = true ;
el.play();
el.removeAttribute('data-autoplay' );
}
}
function Viewport(els, callback) {
this .els = els;
this .callback = callback;
this .active = false ;
var self = this ;
var hidden = [];
function alreadyObserved(el) {
for (var i= 0 ; i< hidden.length; i++ ) {
if (el === hidden[i]) {
return true ;
}
}
return false ;
}
for (var i= 0 ; i < els.length; i++ ) {
var el = els[i];
if (! el.parentNode.style.position) {
el.parentNode.style.position = 'relative' ;
while (el && el.tagName.toLowerCase() !== 'body' ) {
if (window .getComputedStyle( el).display === "none" ) {
if (! alreadyObserved(el)) {
hidden.push(el);
var observer = new MutationObserver(function (mutations) {
if (mutations[0 ].target.style.display !== 'none' ) {
self.handleEvent();
}
});
observer.observe(el, { attributes: true });
break ;
}
}
el = el.parentNode;
}
}
}
this .handleEvent.bind(this );
function ready(f){
/ complete| loaded/ i.test(document .readyState) ? f() : setTimeout(function (){ready(f);},9);
}
ready(function (){self.handleEvent();});
document .addEventListener( 'scroll' , this , true );
window .addEventListener( 'resize' , this , true );
window .addEventListener( 'orientationchange' , this , true );
}
Viewport.prototype = {
isVisible: function (el) {
var style = window .getComputedStyle( el);
return ! ! (el.offsetWidth || el.offsetHeight || el.getClientRects().length);
},
isInViewport: function (el) {
var bounding = el.getBoundingClientRect();
return (
bounding.bottom >= 0 &&
bounding.right >= 0 &&
bounding.top <= (window .innerHeight || document .documentElement.clientHeight) &&
bounding.left <= (window .innerWidth || document .documentElement.clientWidth)
);
},
handleEvent: function () {
if (this .active === false ) {
this .active = true ;
for (var i= 0 ; i < this .els.length; i++ ) {
if (this .isInViewport(this .els[i]) && this .isVisible(this .els[i])) {
this .callback(this .els[i]);
}
}
this .active = false ;
}
}
};
const type = { event: 0 , intersection: 1 , loading: 2 };
var support;
if ("loading" in HTMLImageElement.prototype ) {
console .log( 'native lazy loading' );
support = type.loading;
} else if ("IntersectionObserver" in window ) {
console .log( 'IntersectionObserver lazy loading' );
support = type.intersection;
} else {
console .log( 'Event based lazy loading' );
support = type.event;
}
var images = document .querySelectorAll( "img[data-src]" );
if (images.length > 0 ) {
window .addEventListener( "beforeprint" , function (event) {
for (var i= 0 ; i < images.length; i++ ) {
if (support == type.loading) {
images[i].setAttribute('loading' , 'eager' );
} else {
loadSrc(images[i]);
}
}
function sleep(milliseconds) {
const date = Date .now( );
let currentDate = null ;
do {
currentDate = Date .now( );
} while (currentDate - date < milliseconds);
}
sleep(1000 );
});
if (support == type.loading) {
for (var i= 0 ; i < images.length; i++ ) {
loadSrc(images[i]);
}
} else if (support == type.intersection) {
let lazyobserver = new IntersectionObserver(function (entries, observer) {
for (var i= 0 ; i < entries.length; i++ ) {
if (entries[i].isIntersecting) {
loadSrc(entries[i].target);
lazyobserver.unobserve(entries[i].target);
}
}
},
{
threshold: [0.1 ],
delay: 100
});
for (var i= 0 ; i < images.length; i++ ) {
lazyobserver.observe(images[i]);
}
} else {
new Viewport(images, loadSrc);
}
}
var iframes = document .querySelectorAll( "iframe[data-src]" );
if (iframes.length > 0 ) {
if (support == type.loading) {
for (var i= 0 ; i < iframes.length; i++ ) {
loadSrc(iframes[i]);
}
} else if (support == type.intersection) {
let lazyiframeobserver = new IntersectionObserver(function (entries, observer) {
for (var i= 0 ; i < entries.length; i++ ) {
if (entries[i].isIntersecting) {
loadSrc(entries[i].target);
lazyiframeobserver.unobserve(entries[i].target);
}
}
},
{
threshold: [0.1 ],
delay: 100
});
for (var i= 0 ; i < iframes.length; i++ ) {
lazyiframeobserver.observe(iframes[i]);
}
} else {
new Viewport(iframes, loadSrc);
}
}
var videos = document .querySelectorAll( "video[data-autoplay]" );
if (videos.length > 0 ) {
new Viewport(videos, preloadVideo);
}
})();