18

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.

damian
  • 5,314
  • 5
  • 34
  • 63
  • 1
    It must be img? Is using css background-image an option? – Christoph Jul 14 '15 at 08:28
  • What is the purpose of using a placeholder image for `img` tags that are outside the viewport? If it is memory, could you instead apply `visibility: hidden` or a similar strategy? – Ed Ballot Jul 18 '15 at 19:27

4 Answers4

19

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.

thomasfuchs
  • 5,386
  • 2
  • 18
  • 38
8

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.

Daniel Waghorn
  • 2,997
  • 2
  • 20
  • 33
  • I should have stated that I need valid HTML and an img tag for SEO purposes (updated my question). So basically I need to send an image anyway. I'm just wondering what's better in that case. Loading bas64 encoded placeholders or 1px x 1px images? Both create additional http requests. – damian Jul 14 '15 at 09:46
  • If you're concerned about SEO personally I'd go for the `` tags with base64 as placeholders and then dynamically replace the source. This is the best option with respect to HTTP requests since you'll be saving an additional one for each image as your small placeholder comes along with the actual document. I should have added that if the encoded image is very small it shouldn't have a negative effect on performance. If you were loading e.g. a low-res version of the full image as your encoded image it would however. – Daniel Waghorn Jul 14 '15 at 09:53
  • Perhaps make the placeholder image a 1x1 transparent png image, and give the img tag a width and height of the original image so it takes up the space it will eventually use. I'd prefer your lazy loader merely change the src attribute to the real image path once an image becomes visible, rather than mess around with base64. Browser companies have spent years making images load fast, don't try to bypass them. – Guy Schalnat Jul 16 '15 at 04:11
  • 1
    The only factor that's going to affect how quickly a browser loads an image is the delivery of the data. There's no discernible reason why base64 would be any slower for the browser to interpret than an image loaded via `src` or vice versa. – Daniel Waghorn Jul 16 '15 at 17:59
8

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?)
Community
  • 1
  • 1
LSerni
  • 55,617
  • 10
  • 65
  • 107
2

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.

midzer
  • 347
  • 4
  • 4