Angular Directive to Lazy Load Images
Sunday, January 10, 2021
Angular Directive to Lazy Load Images
I order to improve a page's Time to Interactive (TTI) and First Contentful Paint (FCP) I created an Angular directive that uses the popular lazysizes JavaScript library to lazy load images.
To get started, you need to first install the library via npm (or yarn):
npm i lazysizes
Instructions
checkmark-circle
Use lazysizes to lazy-load image that are offscreen.
info-circle
Lazy loading of resources that are not immediately necessary for the page render improves TTI and FCP.
Code Examples
lazy.directive.ts
import { AfterViewInit, Directive, ElementRef, Input, Renderer2 } from '@angular/core';
import 'lazysizes';
import 'lazysizes/plugins/unveilhooks/ls.unveilhooks';
// tslint:disable:no-input-rename
@Directive({
selector: '[appLazy]'
})
export class LazyDirective implements AfterViewInit {
/** The native element. */
el: HTMLElement | null = null;
/** The HTMLElement background-image value. */
@Input('data-bg') dataBg: string | null = null;
/** The HTMLImageElement sizes attribute. */
@Input('data-sizes') dataSizes: string | null = null;
/** HTMLImageElement src attribute. */
@Input('data-src') src: string | null = null;
/** HTMLImageElement srcset attribute. */
@Input('data-srcset') srcSet: string | null = null;
/** A transparent gif. */
transparent = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==';
constructor(private readonly elementRef: ElementRef, private readonly renderer: Renderer2) {}
ngAfterViewInit(): void {
if (!this.elementRef.nativeElement) {
return;
}
this.el = this.elementRef.nativeElement;
if (this.el.tagName.toUpperCase() === 'IMG') {
(this.el as HTMLImageElement).src = this.transparent;
if (this.dataSizes) {
this.renderer.setAttribute(this.el, 'data-sizes', this.dataSizes);
}
if (this.src) {
this.renderer.setAttribute(this.el, 'data-src', this.src);
}
if (this.srcSet) {
this.renderer.setAttribute(this.el, 'data-srcset', this.srcSet);
}
} else {
this.renderer.setStyle(this.el, 'background-image', `url(${this.transparent})`);
if (this.dataBg) {
this.renderer.setAttribute(this.el, 'data-bg', this.dataBg);
}
}
this.renderer.addClass(this.el, 'lazyload');
}
}
user.component.html
// HTMLElement background
<div class="avatar" lktLazy [data-bg]="user.photoURL"></div>
// HTMLImageElement src
<img lktLazy [data-src]="user.photoURL" [attr.alt]="user.displayName" />
// HTMLImageElement srcset
<img
lktLazy
data-srcset="image1.jpg 300w,
image2.jpg 600w,
image3.jpg 900w"
[attr.alt]="user.displayName"
/>
Have a question or comment?