damian
damian

Reputation: 5444

Source placeholder for lazy loading images

I'm using a lazyload mechanism that only loads the relevant images once they're in the users viewport.

For this I've defined a data-src attribute which links to the original image and a base64 encoded placeholder image as src attribute to make the HTML valid.

<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-src="/path/to/image.png" alt="some text">

I noticed that chrome caches the base64 string but the string is quite long and bloats my HTML (I have a lot of images on a page).

So my question is if it's better to use a small base64 encoded or a 1px x 1px placeholder image?

Note: For SEO purposes the element must be an img. Also my HTML must be valid, so a src attribute is required.

Upvotes: 18

Views: 22495

Answers (4)

midzer
midzer

Reputation: 367

I've experienced good results with inline SVG for responsive image placeholders as described here.

Basically, you put something like

data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 500 500'%3e%3c/svg%3e

in your <img>'s src attribute. Beware to keep viewBox values aspect ratio on par with your real image dimensions. This way your layout won't jump around causing unnecessary repaints.

Upvotes: 3

LSerni
LSerni

Reputation: 57418

I noticed that chrome caches the base64 string but the string is quite long and bloats my HTML (I have a lot of images on a page).

If that is the case, consider placing a 'real' src attribute pointing to always the same placeholder. You do need an extra HTTP request, but:

  1. it will be almost certainly pipelined and take little time.
  2. it will trigger the image caching mechanism, which base64 does not do, so that the image will actually be only decoded once. Not a great issue given today's CPUs and GPUs, but anyway.
  3. it will also be cached as a resource, and with the correct headers, it will stay a long time, giving zero load time in all subsequent page hits from the same client.

If the number of images on a page is significant, you might easily be better off with a "real" image.

I'd go as far as to venture that it will be more compatible with browsers, spiders and what not -- base64 encoding is widely supported, but plain images are even more so.

Even compared with the smallest images you can get in base64, 26 bytes become this

src="data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs="

while you can go from

src="/img/p.png"

all the way to

src="p.png"

which looks quite unbloaty - if such a word even exists.

Test

I have ran a very basic test

<html>
<body>
<?php
    switch($_GET['t']) {
        case 'base64':
            $src = 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=';

            break;
        case 'gif':
            $src = 'p.gif';
            break;
    }
    print str_repeat("<img src=\"{$src}\"/>", $_GET['n']);
?>
</body>
</html>

and I got:

images   mode      DOMContentLoaded   Load      Result
200      base64    202ms              310ms     base64 is best
200      gif       348ms              437ms
1000     base64    559ms              622ms     base64 is best
1000     gif       513ms              632ms
2000     base64    986ms             1033ms     gif is best
2000     gif       811ms              947ms

So, at least on my machine, it would seem I'm giving you a bad advice, since you see no advantages in page load time until you have almost two thousand images.

However:

  • this heavily depends on server and network setup, and even more on actual DOM layout.
  • I only ran one test for each set, which is bad statistics, using Firebug, which is bad methodology - if you want to have solid data, run several dozen page loads in either mode using some Web performance monitoring tool and a clone of your real page.
  • (what about using PNG instead of gif?)

Upvotes: 8

thomasfuchs
thomasfuchs

Reputation: 1

You can use this shorter (but valid!) image in the src tag (1x1 pixel GIF):

data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=

Note that if you gzip your HTML (which you should), the length of the string won't be that important because repetitive strings compress well.

Depending on your needs you might want to use a color for the 1x1 pixel (results in shorter gif files). One way to do this is using Photoshop or a similar tool to create the 1x1 pixel GIF in the right color, and then using a tool like ImageOptim to find the best compression. There's various online tools to convert the resulting file to a data URL.

Upvotes: 19

Daniel Waghorn
Daniel Waghorn

Reputation: 2985

I'd use the placeholder in your situation.

Using the base64 encoded image kind of defeats the purpose of lazy loading since you're still having to send some image data to the browser. If anything this could be detrimental to performance since the image is downloaded as part of the original HTTP request, rather than via a separate request as a browser might make with an image tag and URL.

Ideally if it's just a 'loading' placeholder or something similar I'd create this in CSS and then replace it with the loaded image when the user scrolls down sufficiently as to invoke the loading of that particular image.

Upvotes: 8

Related Questions