How to defer image loading to improve page speed (using AngularJS 1.x)

Artem Kholodenko
Engineering @ BuildZoom
3 min readOct 4, 2016

Squeezing out optimal load times is critical for a heavily trafficked web app. Once you’re past the easy things like caching HTML, compressing assets, deferring JavaScript files, you can start looking at prioritizing above-the-fold content.

One optimization to include in the laundry list of improvements is removing images on the page from being render-blocking and only loading after the load event (not to be confused with the DOMContentLoaded event).

At BuildZoom we currently use AngularJS 1.5.8 as our client-side framework, which will be used in this example. Though the same functionality can be achieved using vanilla JS as well.

There are two common ways to display images via HTML/CSS:

  • HTML img tag
  • CSS background-image attribute

Below are examples of how to defer image loading for both scenarios.

Defer image loading for HTML img

A typical HTML img tag automatically triggers a request for an image based on the value of the src attribute:

<img src="thumbnail.png" />

The goal is to control when the request is made. To do this, the src attribute must be initially omitted and only set after the load event has been triggered by the browser.

Below is an Angular directive, which takes as input the desired value of the src attribute, sets up a listener for the load event, and sets the src attribute of the HTML img element after the event is triggered. Some browsers trigger an onload event instead, so a fallback is in place.

angular.module("myApp").directive('deferImageLoad', [function () {
return {
restrict: 'A',
scope: {},
controllerAs: '$ctrl',
bindToController: {
imageSrc: '@'
},
controller: ['$element', function ($element) {
this.$onInit = function () {
if (window.addEventListener) {
window.addEventListener("load",
this.setImageSrc.bind(this), false);
}
else if (window.attachEvent) {
window.attachEvent("onload",
this.setImageSrc.bind(this));
}
};

this.setImageSrc = function () {
$element.attr('src', this.imageSrc);
};
}]
};
}]);

This directive is leveraged on the HTML img tag, with the image-src attribute replacing src initially:

<img defer-image-load image-src="thumbnail.png"/>

The src attribute is only set after the load event, which prevents the thumbnail.png image from blocking critical content loading on the page first.

Defer image loading for CSS background-image

A typical CSS background-image attribute automatically triggers a request for an image based on the value of the url() input:

.thumbnail {
background-image: url("thumbnail.png");
width: 30px;
height: 20px;
}

The CSS class would be applied to an HTML element:

<div class="thumbnail"></div>

The goal remains the same: control when the request is made.

First, the CSS needs to be updated to only have the background-image attribute on the CSS class that is passed into the deferring directive:

.thumbnail {
width: 30px;
height: 20px;
}
.thumbnail.with-image {
background-image: url("thumbnail.png");
}

Below is a directive, which takes as input the name of the add-on CSS class, sets up a listener for the load event, and adds the CSS class to the HTML element after the load event is triggered:

angular.module("myApp").directive('addClassOnLoad', [function () {
return {
restrict: 'A',
scope: {},
controllerAs: '$ctrl',
bindToController: {
cssClass: '@'
},
controller: ['$element', function ($element) {
this.$onInit = function () {
if (window.addEventListener) {
window.addEventListener("load",
this.addClassToElement.bind(this), false);
}
else if (window.attachEvent) {
window.attachEvent("onload",
this.addClassToElement.bind(this));
}
};

this.addClassToElement = function () {
$element.addClass(this.cssClass);
};
}]
};
}]);

The addClassOnLoad directive is then leveraged on the HTML element:

<div add-class-on-load css-class="with-image"
class="thumbnail"></div>

The with-image class is only added after the load event, which prevents the thumbnail.png image from blocking critical content loading on the page first.

--

--