Most WordPress themes show user Gravatars in the comment threads. It’s a way of showing an image with the user, as associated by the email address used. It’s a nice touch, and almost an expected design pattern these days.
Every one of those gravatars is an individual HTTP request though, like any other image. A comment thread with 50 comments means 50 HTTP requests, and they aren’t always particularly tiny files. Yeesh.
Let’s lazy load them.
The Concept
Lazy loading is the idea that you don’t even request the image at all (no HTTP request) unless the image is visible. Meaning that, through JavaScript, we’ve determined the image is visible.

In order to stop those HTTP requests for not-yet-seen images, we need to get our hands directly on the markup. If there is an <img src="">
in the HTML, there is essentially no way to stop the browser from downloading that image as soon as it possibly can, seen or unseen. So, we need to remove that src
, and put it back when we’re ready.
Woah, There
It’s worth a pause here because we’ve entered some murky territory.
By removing the src
of these images, and only ever putting it back with JavaScript, we’ve decided that we’re willing to ship slightly invalid HTML and rely 100% on a script downloading and executing for these images to ever be seen.
I’m OK with that. Mostly because gravatars are just an enhancement anyway. It ain’t no big deal if they never show up. I’m not a hardliner most JavaScript debates, but this seems like a particularly clear case where we can lean on JavaScript without worry.
Altering the HTML
This is the change we’d be making:
<!-- Normal image. No beating the browser preloader. -->
<img src="https://gravatar.whatever..." alt="" />
<!-- Let's change to this, which won't download anything. -->
<img data-src="https://gravatar.whatever..." alt="" />
Although a missing src
on the <img>
is technically invalid HTML. It almost certainly doesn’t really matter in that it won’t affect how anything works. If the invalid HTML bugs, you could always toss a super minimal blank GIF data URL in there, like:
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" ... />
Using width
and height
attributes is probably a good idea too, to maintain layout and avoid reflow if and when the images to load.
Altering the HTML… in WordPress
But how do you change the HTML that WordPress spits out as part of a comment thread? Comments are slightly unusual in WordPress in that WordPress core gives you the HTML, it isn’t part of your theme like most of the other HTML is.
Likely, in your `comments.php` file, you’ll see this function:
<?php wp_list_comments(); ?>
Which spits out a pile of <li>
‘s with your entire comment thread. Not a lot of opportunity there to be fiddling with the output of images. Except, we can! We can list a callback function in there:
<?php wp_list_comments('callback=csstricks_comment'); ?>
That callback is the name of a function we can toss in our `functions.php` file. Here’s an example of that function, which must return a <li>
:
function csstricks_comment($comment, $args, $depth) {
$GLOBALS['comment'] = $comment; ?>
<li <?php comment_class(); ?>">
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" width="50" height="50" class="lazyload-gravatar" alt="User Avatar" data-src="<?php echo get_avatar_url(get_comment_author_email($comment_ID), array("size" => 160)); ?>">
<?php comment_text(); ?>
<?php # phantom </li> ?>
<?php }
That’s very simplified, but you can see what we’ve done. We replaced the src
with the blank GIF, we’ve added a class
name we’ll ultimately use in JavaScript to do the lazy loading, we’ve added a data-src
to the actual gravatar, and we’re using width
and height
attributes for placeholding. Here’s my actual complete callback live right now on CSS-Tricks.
If we shipped this right now, sans any JavaScript work, we’d still have a perfectly functional comment thread, just with images that never load.
Now We’re Ready to Lazyload
The hard part is over. We’re perfectly set up to do lazyloading now. If we were to write a script, it would be like:
- Figure out the visible area of the browser window
- Figure out the position on the page of every image with class
.lazyload-gravatar
- If any of those images are in the visible area, flop out the src with the value from data-src
- If the visible area of the browser window changes in any way, re-evaluate the above
We could set about writing that ourselves. And we could do it! But, and I’m sure you’re not surprised here, it’s a bit tricky and nuanced. Cross-browser concerns, performance concerns, does-it-work-on-mobile concerns, to name a few. This is the kind of thing I’m happy to lean on other’s work for, rather than roll myself.
Again, no surprise, there are loads of options to pick from. In my case, I’m happily using jQuery on CSS-Tricks, and I picked a jQuery-based on that looked pretty good to me:

The API is as simple as can be. After bundled up the lib with the rest of the libs I’m using, I just call:
$('.lazyload-gravatar').Lazy();
Look how nicely it works!
That’s an awful lot of saved HTTP requests and awful good for performance.
Makes you wish web standards and browsers would get together on this and make it a native feature.
Nice post – gravatars are definitely a good candidate for lazy loading as some users may not even see them at all, saving a lot of load time and data.
One thing I’d recommend is instead of removing the src altogether, replace it with a placeholder, such as this one – http://www.dfhtechnologies.com/images/user.png
That way you’re still shipping valid HTML, if the script breaks at least something is still visible and you can still enhance with JavaScript. It’s win win!
He used a data url for this. It looks less fancy but if all goes well the user shouldn’t even see the image anyway.
It also saves a http request.
Matter of preference i suppose ;)
True, but I think we should also account for the case where all does not go well.
Slow data connection, browser support and firewalls can all stop a JavaScript file downloading and running smoothly.
See https://kryogenix.org/code/browser/everyonehasjs.html for more.
By using a placeholder image rather than a blank gif, the page looks complete rather than broken, even if the JavaScript fails.
And if saving a HTTP request is important, you can convert the placeholder image into a data URL as well.
I was hoping for the script to be just a little smarter.
Right now they scroll in blank and take half a second to show.
Could you expand the range and fetch them when they are near 20vmax (for example) of the visible area?
Did you see the
threshold
option you can set when initialising the plugin?Setting something like the below should do the trick. N.B. This is untested
Great article ! Lazy loading works very well in this case and it’s surprisingly quite simple.
And I agree with Adam Taylor, using a placeholder would allow you to output valid HTML and it would look better than with a blank GIF.
Great write-up about the why and the possible problems.
Some suggestions that I learned from a developer at tweakers.net (Dutch site) that I’d love to share that could remove some of the problems.
Instead of gif(Adam’s suggestion is great as well), you could use data:svg. You can give it the actual image dimensions.
Second, for non-js users you could pass in the real version of the image using a noscript tag. All you need is a very basic check if JS is turned on to start showing the version of the image that’s not in the noscript-tag.
$tmpSrc = "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'"
. " width='{$width}' height='{$height}'/%3E";
<noscript>
<img width='<?=$width?>' height='<?=$height?>' alt="<?=$alt?>" src="<?=$src?>">
</noscript>
<img width='<?=$width?>' height='<?=$height?>' alt="<?=$alt?>" src="<?=$tmpSrc?>" data-aym-lazy="<?=$src?>">
And css
.no-js noscript + img {
display: none;
}
The variables $width and $height etc are all passed from another piece of code that does its best to find those values from any image, even svg.
Hoping I can comment on my own unmoderated comment.
I didn’t really specify why you’d want to have actual image dimensions. This is especially useful for places where you need images to be responsive fitted in the browser.
Take for example an image that’s 2000px wide and 500px high. Usually in your css you would declare something like this:
img {
width: 100%;
height: auto;
}
What would happen if we put in the temporary image like so in a 1000px wide window?:
<img src='tmpimage1pxsquare.gif' width=2000 height=500 lazy-src='actualimage.jpg'>
The given width and height attributes don’t work because they’re overridden by the css.
The result is a temporary image of 1000px X 1000px that’s later transformed to 1000px X 250px when the original image is loaded.
New territory for me. Interesting. Except I don’t see any gravitars on THIS page (using Firefox 52.0.2) – Is my firefox a browser you’ve written off as merely cosmetic or is this a bug?
Check your blocker add-ons. Some block gravatars.
:rolling-eyes-emoji: