Don't sleep on native lazy loading iframes
Tags: webdev, html, performance
Published: 2024-01-23 09:30:00


Perhaps I am wrong, but I think that many people are unaware of native lazy loading of iframes. I think it has flown under the radar. I guess lazy loading of images was more front and center because images are the most popular resource type on the web and make up the majority of the weight of a typical webpage. But what about the venerable `iframe`?

## Native lazy load an `iframe`

Before we go further, it is worthwhile stating what an `iframe` is. It is *not* an Apple product! 😉

![Steve Jobs doing a strange movement, touching his shoe, and laughing](https://www.roboleary.net/assets/img/blog/2024-01-21-lazy-load-iframes/steve-jobs.webp)

An `iframe` is a nested browsing context. A browsing context is a complete document environment, it can load its own resources - images, fonts, JavaScript - the same resources as a regular webpage.

An iframe is not lightweight! Every `iframe` in a page requires increased memory and some computing resources. If you overdo the usage of iframes in a page, it can led to performance problems. So, if we can avoid loading iframes initially through lazy loading, we can improve the speed of the initial page load.

The good news is that similar to images, the `loading` attribute is used on the `iframe` element for lazy loading. To mark an `iframe` as a canidate for lazy loading, just add `loading=lazy` to the opening tag.

```html
<iframe loading="lazy" width="560" height="315" 
	src="https://www.adtube.com/embed/eHzoT" 
	title="A lazy loaded iframe bruh">
</iframe>
```

The supported values for the `loading` attribute are:

- `lazy`: Defer loading of the resource until it reaches a calculated distance from the viewport.
- `eager`: This is the default loading behavior of the browser. This is the same as not including the attribute and means the iframe is loaded regardless of where it's located on the page. While this is the default, it can be useful to explicitly set this if your tooling automatically adds `loading="lazy"`.

In the last month, it has landed in all 3 browser engines.

![can i use table for lazy loading for iframe](https://www.roboleary.net/assets/img/blog/2024-01-21-lazy-load-iframes/loading-lazy-attr-iframe-caniuse.webp)

### Avoid lazy loading iframes that are in the initial viewport

I suggest that you follow the same advice given for images, and avoid adding `loading=lazy` to iframes that are in the viewport when a page loads.

If you want to roll out lazy loading iframes on a website, I would run some A/B tests to verify everything is as you expect. There may be a difference between using `loading=eager` and omitting the attribute altogether for iframes that are in the initial viewport. It is was just added for Safari and Firefox, so a bit of caution is wise for now.

## What is the performance improvement of lazy loading iframes?

To gauge the impact, I did an A/B test on my blog. I picked my biggest blog post which is my [Stranger Things animation tutorial]({% post_url "2023-05-30-how-to-make-a-slick-animation-stranger-things-title-sequence.md" %}). It is a huge post that has 14 codepens! 😅  You should avoid making pages like this generally!

I use an `iframe` embed for codepens. All the iframes are in the page from the get go, no scripts adds them on the client side.

I did the performance testing using [WebPageTest](https://www.webpagetest.org/). This is a lab test, so don't take the results too literally as it does not reflect real world usage. It does 3 runs and takes the median result of the runs to reduce variability. In the first test, I tested without lazy loading on the codepens. In the second test, I added lazy loading to 13 out of the 14 codepens - I excluded the first one. I used the same conditions for both tests, testing on my public website.


| State | WebPageTest result   | First Contentful Paint | Speed Index  | Total Blocking Time | Page Weight |
|-------------- |-------------- | -------------- | -------------- |-------------- |-------------- |
| Without lazy loading | [result](https://www.webpagetest.org/result/240118_AiDcCF_E4R/)  |  2.395s   | 2.4s | 10.320s | 930KB |
| With lazy loading | [result](https://www.webpagetest.org/result/240118_BiDcN1_E34/)     | 2.038s  | 2.126s     | 1.032s | 428KB |


As you can see, it has a major impact on a large page. It cuts [First Contentful Paint](https://web.dev/articles/fcp) by approxmiately 15%, that can push your Core Web Vitals score towards the green. The biggest change is the [Total Blocking Time](https://web.dev/articles/tbt) -- from 10 seconds to 1 second -- having a page being unresponsive to input for that period is unacceptable! And page weight is down 50%. This page would really suck on low-powered devices without lazy loading!

I think it is useful to see the impact on a large page to grasp the magnitude of the potential improvement. On a typical page with a couple of iframes, the performance boost will be a lot more modest of course, but it does add up. The key takeaway is that the bang for buck is high -- the effort is low to add an attribute to an element.

## Graceful degradation - its a toll-free addition

The phrase graceful degradation still doesn't sit with me comfortably, you can consider native lazy loading as a toll-free addition. Browsers that do not support the `loading` attribute will ignore its presence. While browsers that support it, will give you a performance bump. There is no negative impact, with the exception of browser bugs.

## Lazy loading third-party embeds

Probably the number one usage of iframes on websites is from third-party embeds such as YouTube videos, tweets (from X, formerly Twitter), code demos (codepen, JSFiddle, and so on), and many more. It might be worthwhile reviewing them with lazy loading in mind.

<figure>
![embed dialog for youtube](https://www.roboleary.net/assets/img/blog/2024-01-21-lazy-load-iframes/youtube-embed-dialog.webp)
<figcaption>The dialog for sharing an embedded video on YouTube. The embed snippet is an <code>iframe</code>. It does <em>not include</em> the <code>loading</code> attribute.</figcaption>
</figure>

Some services like YouTube just offer an `iframe` embed, while others offer a HTML embed. The HTML embed is usally a `div` with some data attributes, and has a script that transforms the `div` into an `iframe`. The script can do other stuff too of course!

<figure>
![embed dialog for codepen](https://www.roboleary.net/assets/img/blog/2024-01-21-lazy-load-iframes/codepen-embed-dialog.png)
<figcaption>Codepen offers different embed options.</figcaption>
</figure>

I had at look at a few and found that:
- Youtube does not include lazy loading,
- Codepen includes lazy loading for both the HTML embed and iframe embed.
- JSFiddle does not include lazy loading.

It easier to use a component or shortcode for embeds on websites. Then you can update the component to provide better defaults and add new features such as lazy loading. No need to do a global find-and-replace with some funky regex to get all instances to do the same thing.

## Conclusion

Since iframes are taxing on page performance, a significant performance saving can be made if you lazy load them. It is low-hanging fruit for improving perf. In my test, on my biggest blog post with (too) many iframes - adding lazy loading cut First Contentful Paint by 15%, reduced Total Blocking Time by 90%, and shred page weight by 50%.

You use lazy loading on iframes the exact same way as do for images. You use the `loading` attribute, just add `loading=lazy` to the opening tag.

It is supported by all 3 browser engines now. The `loading` attribute will degrade gracefully -- browsers that do not support it will ignore its presence.

I would recommend that you follow the same advice given for images, and avoid adding `loading=lazy` to iframes that are in the viewport when a page loads. Doing so may have a negative impact on perf.

So, go ahead, make the web faster! Or are you too lazy?🦥😉

---

Written by [Rob O'Leary](https://www.roboleary.net)

[Subscribe to web feed](https://www.roboleary.net/feed.xml) for the latest articles.

<small>© Rob OLeary 2024</small>