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.
Install lazysizes
To get started, you need to first install the library via npm (or yarn):
npm i lazysizes
LazyDirective
Next, create a new lazy.directive.ts file:
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');
}
}
Implement lazy loading
Finally, here is the implementation in a template:
<!-- 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"
/>
Learn in Public
If you're like me, you are constantly learning. Further, I love to share what I learn in public.
My biggest roadblock to learning in public is taking the time to write a long blogpost. So, I made lookout.dev to make it easy to learn in public.
Checkout my other lookouts, along with the lookout to create an Angular Directive to lazy load images with Angular.
Cheers!
Top comments (0)