Skip to content

Instantly share code, notes, and snippets.

@shiftgeist
Last active September 19, 2024 10:48
Show Gist options
  • Save shiftgeist/3131473bc820f7df9cba26881ae46284 to your computer and use it in GitHub Desktop.
Save shiftgeist/3131473bc820f7df9cba26881ae46284 to your computer and use it in GitHub Desktop.
Minimal lazy load images
// Based on https://github.com/ApoorvSaxena/lozad.js
interface Options {
selector: string;
rootMargin: IntersectionObserverInit['rootMargin'];
threshold: IntersectionObserverInit['threshold'];
load(target: Element): void;
loaded(target: Element): void;
}
const defaultConfig: Options = {
selector: '.lazyload',
rootMargin: '100%',
threshold: 0,
load(element: HTMLImageElement) {
const src = element.getAttribute('data-src');
if (src) {
element.src = src;
}
},
loaded() {},
};
function markAsLoaded(element: Element) {
element.setAttribute('data-loaded', 'true');
}
const isLoaded = (element: Element) => element.getAttribute('data-loaded') === 'true';
const onIntersection =
(load: Options['load'], loaded: Options['loaded']) =>
(entries: IntersectionObserverEntry[], observer: IntersectionObserver) => {
entries.forEach((entry) => {
if (entry.intersectionRatio > 0 || entry.isIntersecting) {
observer.unobserve(entry.target);
if (!isLoaded(entry.target)) {
load(entry.target);
markAsLoaded(entry.target);
loaded(entry.target);
}
}
});
};
export const lazyload = (options: Partial<Options> = {}) => {
const { rootMargin, threshold, load, loaded, selector } = Object.assign(
{},
defaultConfig,
options,
);
if (!window || !document) {
throw Error('[lazyload] window not defined');
}
// If IntersectionObserver is unavailable load images instantly
if (!window.IntersectionObserver) {
for (const el of document.querySelectorAll(selector)) {
load(el);
markAsLoaded(el);
loaded(el);
}
}
const observer = new IntersectionObserver(onIntersection(load, loaded), {
rootMargin,
threshold,
});
return {
observe() {
for (const el of document.querySelectorAll(selector)) {
if (isLoaded(el)) {
continue;
}
if (observer) {
observer.observe(el);
continue;
}
load(el);
markAsLoaded(el);
loaded(el);
}
},
triggerLoad(element: Element) {
if (isLoaded(element)) {
return;
}
load(element);
markAsLoaded(element);
loaded(element);
},
observer,
};
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment