Lazy Loading Images

Angular: The Full Gamut Edition

Charlie Greenman
August 30, 2020
5 min read

Even though we discussed lazy loading modules, we might also want to lazy load the content inside of the lazily loaded modules. There is a very popular article from Google that is generally spread around with regards to performance for webpages. In short, it presents the following very persuasive set of data:

@ l *4c @ As page load time increases\ Seconds & Probability of Bounce\ 1s to 3s & Increases by 32%\ 1s to 5s & Increases by 90%\ 1s to 6s & Increases by 106%\ 1s to 10s & Increases by 123%\

As we can see with the data presented above, performance of our webpages are very important. More so it presents the data very clearly that the faster a webpage is, the higher probability there is to retain our user base.

The Idea of Lazy Loading Images

There are, of course, many different ways to increase performance. The intent of this chapter, however, is just to discuss the one performance boost that is gained by lazy loading images. The idea of lazy loading images, similar to lazy loading modules in general, is to load an image only when a user get's to that image.

It is important to note, that we do not want to lazy load all images that are present on our page. For instance, imagine that we were creating a blog for our website. On each single blog page, we have a feature image that shows up first for our blog. In addition, we have more images that show up throughout the remainder of the blog. It can be strongly argued that lazy loading should not be applied to the feature image. Because, it would potentially cause an awkward experience for the user, to load the page and then wait an additional second to see what the feature image looks like.

Therefore, when creating lazy loaded images, it is important to not create a blanket rule that will apply to all images. Rather, those images which are not primary to the page, those should be lazy loaded.

Real Talk - Implementing Lazy Loading

Within Angular, there would be a way to implement lazy loading from scratch.

The simplest solution I've seen is wrapping an Angular Directive around the Intersection Observer api. It will allow you to determine when an element is in the viewport. This approach, works great, however, there are readily available npm plugins that do this for Angular. While the author of the aforementioned article did create their own plugin there is another that is much more mature. It implements the intersection observer as well, and is called ng-lazyload-image.

ng-lazyload-images

Razroo's preferred package is ng-lazyload-image. It is the most mature of all packages in the Angular eco-system, has the most stars, and fantastic documentation.

Install

npm install ng-lazyload-image --save

Setup

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { LazyLoadImageModule } from 'ng-lazyload-image'; // <-- import it
import { AppComponent } from './app.component';

@NgModule({
    declarations: [ AppComponent ],
    imports: [ BrowserModule, LazyLoadImageModule ], // <-- and include it
    bootstrap: [ AppComponent ]
})
export class MyAppModule {}
  import { NgModule } from '@angular/core';
  import { BrowserModule } from '@angular/platform-browser';
  import { LazyLoadImageModule, intersectionObserverPreset } from 'ng-lazyload-image'; // <-- include intersectionObserverPreset
  import { AppComponent } from './app.component';
  
  @NgModule({
      declarations: [ AppComponent ],
      imports: [
        BrowserModule,
        LazyLoadImageModule.forRoot({
          preset: intersectionObserverPreset // <-- tell LazyLoadImage that you want to use IntersectionObserver
        })
      ],
      bootstrap: [ AppComponent ]
  })
  export class MyAppModule {}

Example Use Case

The following is an example use case, of how to create a lazy loaded image with ng-lazy-load:

import { Component } from '@angular/core';

@Component({
  selector: 'image',
  template: `
    <img [defaultImage]="defaultImage" [lazyLoad]="image">
  `
})
class ImageComponent {
  defaultImage = 'https://www.placecage.com/1000/1000';
  image = 'https://images.unsplash.com/photo-1443890923422-7819ed4101c0?fm=jpg';
}

The package also has examples for multiple other use cases such as background images, responsive images, async images(i.e. | async) etc.

Transitioning Photos

Something that you might want to do is add a transition to your photo, so that it swaps out the defaultImage with the lazyLoaded image. Doing something like this would be relatively straightforward. For instance:

img.ng-lazyloaded {
  animation: fadein .5s;
}
@keyframes fadein {
  from { opacity: 0; }
  to   { opacity: 1; }
}  

That is all it would take to put a transition effect on your photos.

Hooking Up Lazy Loading To Our Back End

In short, you would get all image urls from the actual GraphQL query. You would put them underneath the lazyload directive. Just like that you have lazy loaded configured.

Subscribe to the Razroo Angular Newsletter!

Razroo takes pride in it's Angular newsletter, and we really pour heart and soul into it. Pass along your e-mail to recieve it in the mail. Our commitment, is to keep you up to date with the latest in Angular, so you don't have to.

More articles similar to this