What is Native Lazy-Loading?
When a browser opens a webpage, it normally loads every image on it—even ones far below the visible area, or viewport. Some visitors might not ever scroll further down the page, which means the bandwidth spent loading those unseen images is wasted.
The situation changed with the arrival of Chrome 76. From that version onward, Chrome and Chromium-derived browsers support native lazy-loading. All you have to do is add a single attribute to your image tags:
It's that simple. And if a different browser doesn't support the new attribute yet, the images will load normally, no harm done.
Now I'll tell you how to add these attributes to your images in Wordpress automatically (for the most part).
March 2020 Update (Read First!)
There have been exciting developments since this article was written. Native image lazy-loading has become a part of the official HTML spec. Browser support has improved. And perhaps most importantly, native lazy-loading is to be merged into WordPress core as of version 5.5.
In practical terms, this means that no extra effort your part will be necessary after WP version 5.5 arrives in August 2020. Until then, you can test native lazy-loading by using the modifications described below. Just keep in mind that hey will become irrelevant in several months (and hooray for that).
Native Lazyload Plugin
First off, Google's own Native Lazyload plugin can do all the work for you. At the time of writing, it's rife with one-star reviews claiming it broke their site, but I'm sure it will get fixed eventually. Even then, I won't use it because I'm a curmudgeon and avoid installing plugins as much as possible, but if you're looking for the fastest and easiest solution, this is it.
1. Add Lazy Loading Attribute to Featured Images and Attachments
Adding the loading="lazy" attribute to featured images (previously called post thumbnails), galleries, and images on attachment pages is easy by using the wp_get_attachment_image_attributes hook. Simply copy and paste the code below into your theme's functions.php file:
Kudos to akkis on Wordpress Code Reference for this snippet.
You can verify that this works by inspecting the source code of a featured image or an attachment page on your site:
2. Add Lazy Loading Attribute to New Images Inside Posts
The code above doesn't affect single images added via post editor. For that I've used the image_send_to_editor hook as shown below. Add it to functions.php like before.
What this does is simply tack on the loading="lazy" attribute whenever inserting an image into a post via "Add media". When you switch to "Text" in Classic Editor or click the three dots and then "Edit as HTML" in Gutenberg, you'll see something along these lines:
As you might've guessed, this only affects newly inserted images. Galleries and post thumbnails aside, existing images in older posts won't receive the lazy loading treatment. There's a good reason for this: Images inserted into posts are essentially a part of the post text and can't be filtered directly.
You can, of course, use a function that searches the contents of an entire post and tacks on the lazy loading attribute to each <img> tag it finds, but that strikes me as inefficient. The process would have to be repeated each time a visitor views a post, putting undue load on your server and slowing your site, which is the opposite of what we're trying to do. This approach is much easier, however, so I've added such a function further below in case you'd like to use it.
3. Lazy Loading for Existing Images in Posts
To deal with existing images in older Wordpress posts, I can't really think of anything smarter than doing a simple search & replace. (If you have a better idea, please share it in the comments!) This might not seem very elegant, and it hardcodes the loading="lazy" attribute into posts, but it only has to be done once.
To this end, I've used a plugin called Better Search Replace on my wp_posts table as follows:
If you're going to do this at all, it's best to do it before you modify the editor as described in Step 2, or you'll get image tags with duplicating attributes. Again, only do this once.
And if this attribute never gains mainstream support, you can always remove it from your posts by performing the search & replace in reverse.
Easier Alternative for All Images in Posts
But let's say you use a good caching plugin so the cost of searching through the post text with each page load doesn't apply. In that case you can use the_content filter to search every post for image tags and tack on the lazy loading attribute on the fly. Simply add the following function to your functions.php file:
If you use this approach, you can skip steps 2 & 3 because this function will automatically add the loading="lazy" attribute to every image on every post.
4. Lazy Loading for Commenter Avatars
Comments are usually located at the bottom of the page, so user avatars are a good target for lazy loading. You could use this filter in your functions.php:
Or, if your theme uses a custom comment callback, you might find the get_avatar() function and add loading="lazy" to it through the extra_attr parameter.
If you're using a more modern comment system like Disqus, this isn't necessary.
5. Lazy Loading Youtube Videos
One thing I haven't mentioned so far is that lazy loading can also be applied to iframes. When you paste a link to a video on Youtube (or other supported site), Wordpress automatically turns it into an iframe to embed it on your post. To make it load lazily, we can use the embed_oembed_html filter as follows:
Verifying the Improvement
There are several ways to test if lazy loading works. The easiest is to open your website in the latest version of Chrome, fire up the Developer tools (Ctrl + Shift + I), and switch to the Network tab. Navigate to a long page with a lot of images and scroll down. You should see that the images at the far bottom won't load until you scroll lower.
An alternative way is to launch an Audit via the same developer tools, or use the web-based PageSpeed Insights test. Look for the "Defer offscreen images" message, which will show up in the "Opportunities" section if not yet implemented, and in the "Passed audits" section if lazy loading is working.