Check out a free preview of the full Web Performance Fundamentals course:
The "Defer & Lazy Load Practice" Lesson is part of the full, Web Performance Fundamentals course featured in this preview video. Here's what you'd learn in this lesson:

Todd explains the loading attribute for lazy loading images is not compatible with some browsers so it's recommended to lazy load with JavaScript. The IntersectionObserver object detects when an element is within the viewport. When this occurs, the element's src attribute can be updated to trigger the loading of the resource.

Get Unlimited Access Now

Transcript from the "Defer & Lazy Load Practice" Lesson

[00:00:01]
>> Unfortunately, there's a huge red flag that keeps us, from using loading dot loading equals lazy, and that's this, the compatibility table of the loading attribute. So it's this really annoying one red thing, that happens to be a red thing that will block us from using it, which is Safari.

[00:00:19] If it works in Chrome, it works in Edge, it works in Firefox, it works in Android, it won't work on iOS, or on Macs. And if it won't work on iOS or on Macs, it's kind of a deal killer, so we need a different way to do this.

[00:00:33] Fortunately, JavaScript to the rescue, we can solve this problem with JavaScript. We're gonna do another code exercise together, and play with that, so back in our project. In the utility folder, public assets JS detail, I have another little utility, that I bring around from project to project, that happens to solve this particular problem for us.

[00:01:01] It's called lazy loader, and we're gonna walk through briefly how it works, and then we're gonna apply it together. And we're gonna actually change the order of our document, and see some improvements. So the top of this is that, same snippet of code or very similar snippet of code that we saw with the performance agent.

[00:01:19] This is a bit of incantation that's basically equivalent to jQuery.ready, it's saying, hey, wait until the document is ready before we do anything. And then it starts looking at the page, and we're trying to find things that we want to be leisurely loaded. So we look for anything on the page, that happens to contain the attribute.

[00:01:44] Data dash source, not source not SRC, like a regular image would have, but data dot source, and so we have all these lazy elements. And what we're gonna do is, we're gonna create what's called a, intersection observer, if it exists, it might not exist on all browsers. But most modern browsers have intersection observer, and intersection observer allows us to detect is an element inside the view frame.

[00:02:16] Can this element be seen, so, we're gonna create a intersection observer for each of the lazy elements that we found. And whenever, that element that is a has a data source attribute is intersecting, then we're going to load it, and turn off our observer. The load function, essentially just copies the value from data dot source and, data source set, which we'll talk about in the future, into their real attributes.

[00:02:54] So essentially, we have an image file, that doesn't have a source, until it intersects, and then we write a source into it, and the browser will go and download it. So we can utilize this, by changing any of our elements from source to data source, will essentially tell this thing to lazily load itself.

[00:03:17] So let's apply that, let's figure out how to use that, if we look at our page, and we load it. All of these annoying things, what images do we need to load, well, you should probably load the logo. And we should load this cool picture of the sloth on a rocket, it's part of the main content.

[00:03:40] But if we scroll down, there's this YouTube video, that we probably don't need to load. And then there's like, these big images showing off features, we probably don't need to load them yet. And this really concerned sloths, we probably don't need to load him either, and sloths looking at a blueprint, we probably don't need to load him either.

[00:04:00] And the pricing one, we don't need to load him either. We can differ tonnes of these images, and not load them right, now and focus on the two images, the logo and the rocket. They're important at the beginning, so let's look at our index dot HTML and how we would do that.

[00:04:21] So here we have our header, in the header we have the request metrics logo. We wanna keep that, we want that to load as fast as possible, we are gonna leave that exactly as it is. As we scroll down, we see our flying sloth, or our sloth on a rocket is just a background image here, as part of our main top part of our document.

[00:04:43] So we wanna leave that, let's keep going, here we have a YouTube video, a YouTube embed. Now the cool thing about the lazy loader script, is it doesn't care what kind of element if we want to load lazy. It's not, it doesn't just support images, it could support anything that has a source, like an iframe, we don't necessarily need to load this YouTube iframe right away.

[00:05:08] So we can slow it down by saying data source. Now, some browsers really dislike when an element that needs a source doesn't have a source, so we can create an empty source attribute like that. When the browser interprets this, it's gonna say, hey, I have an iframe, and I don't need to load anything, so I'm not going to do anything.

[00:05:30] And this is just a bit of data for later, but when this element intersects, when it's visible, our script will copy the value into source. And the browser will load it as it normally would, essentially, delaying the value until when you need it. Let's keep going down, here we have our call-outs, our different features that we want to show off.

[00:05:56] So here we have some images, we can do the same thing, we're just gonna change source to data source, and put a empty source attribute in there. Now copy this so we can go a little faster, there's 1, 2, 3 of these, we have the sloth looking concerned, we'll do that there as well, Sloths building a rocket.

[00:06:33] And that's it, cool, all right, so we've changed several of the images that are below the fold to have this value. Now we need to add our lazy loader, so that this works, so for now, at the top of the document with all of our scripts, let's just put our lazy loader in here as well.

[00:06:55] So it's right next to our purpose, I'm just gonna call it lazy loader, dot j s and put it right there. This is not the only thing that we talked about deferring, we also talked about deferring the scripts. None of these things, really need to be there immediately, right, we don't need to capture performance before page load.

[00:07:20] We don't need to initialize our lazy loader until page load, we probably don't need to render the banner, or load our chat script or any of the jobs. None of this needs to be happening first, so why does it, let's just take all of this, all of these scripts.

[00:07:38] And we'll cut them out of the head, and go all the way down to the very end, and just below it, before we close the body, let's put them all here. So the browser doesn't even start worrying about JavaScript, until the content is all like put together. And we can go a step further and say, hey, don't even execute these, don't execute these until we're ready, and let's put the defer attribute on all of them.

[00:08:09] Don't forget chatty here at the bottom. So all of these are in place, all of these are now loaded. If we go back to our HTML, and reload the page. Visually I can't see a difference yet, because my pages too fast right now, but chances are slower users will definitely see this impact.

[00:08:42] So let's prove that, let's go and take a look at lighthouse again, now, before we made these changes, I was getting a 95. If it was point 6 and point 9 and point 2, 6 were my scores, let's run this again. Now that we've made this differing update, I'm gonna hit plus, and generate a new report.

[00:09:04] All right, so my lighthouse is finished, and we gained two points in performance, we did a little bit better. Our first contentful paint change, but that's just some natural variability, largest contentful paint changed a little bit. That's some natural variability, the time to interactive went way down, total blocking time went way down.

[00:09:23] If we go and take a look at our trace, look at how much fewer, how many fewer things need to happen here Most of that busy work is now pushed down the page, it is less important. So essentially, what we did was we took all of these nasty elements over here.

[00:09:46] These other images, this extra JavaScript that was coming down, we removed it from our critical path, we have fewer things to do. Now, this isn't gonna improve performance for every user, but it will prove performance for most users. Over a large data set, we're gonna see the total, or the median, and the P 75, lcps, come way down, because there's fewer things that can block.