Lazy Load Images with Angular

blove

Brian Love

Posted on January 26, 2021

Lazy Load Images with Angular

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
Enter fullscreen mode Exit fullscreen mode

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');
  }
}
Enter fullscreen mode Exit fullscreen mode

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"
/>
Enter fullscreen mode Exit fullscreen mode

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!

💖 💪 🙅 🚩
blove
Brian Love

Posted on January 26, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

Lazy Load Images with Angular
webperf Lazy Load Images with Angular

January 26, 2021