Christian Heilmann

Quick trick: using template to delay loading of images

Tuesday, September 8th, 2015 at 1:34 am

In addition to this explanation, I also recorded a quick screencast. Feel free to check that one first.

When it comes to newer elements to play with there are a few that are slightly odd. Canvas is one of them, as it doesn’t do anything without scripting. It is a placeholder for a canvas painting or animation and can contain fallback content when it is not supported. This ailed purists of semantic HTML when it came out, because – to a degree – this was just a rehash of applet or object we used with Java or Flash.

Template is an even weirder thing. Using template you can define inert content in HTML - this means the content is not rendered by the browser, and anything inside it is not executed (for example script elements). Again, this is something that can annoy purists, as this content only makes sense when JavaScript is available. But, to people who are used to templating in other languages, this is a great opportunity.

The biggest issue with template is that it can’t really by polyfilled as browsers that don’t know template, treat it like a DIV and render its content. In the past we simulated this functionality with script elements with a type of text/html as those will be skipped by browsers.

For more info about template itself, check these resources:

One thing you can do with template is to put content in it that is “nice to have” but would delay the loading of the page and especially the firing of the onload handler.

I’ve done this in the Cuter demo of Tinderesque. This demo loads a lot of images, and not all of them need to be available right away. That’s why I put five of them in the document and wrapped the rest in a template:

<ul class="cardlist">
  <li class="card current"><img src="images/a-push-please.jpg" alt=""></li>
  <li class="card"><img src="images/amazing-dog.jpg" alt=""></li>
  <li class="card"><img src="images/awesome-mix-dog.jpg" alt=""></li>
  <li class="card"><img src="images/baby-amardillo.jpg" alt=""></li>
  <li class="card"><img src="images/baby-hippo-nom.jpg" alt=""></li>
  <template>
    <li class="card"><img src="images/baby-rhino.jpg" alt=""></li>
    <li class="card"><img src="images/barbie-frenchie.jpg" alt=""></li>
    <li class="card"><img src="images/basset-helmet.jpg" alt=""></li>
    <li class="card"><img src="images/bear-dog.jpg" alt=""></li>
    <li class="card"><img src="images/bear-puppy-fluff.jpg" alt=""></li>
    <li class="card"><img src="images/best-day-ever-puppy.jpg" alt=""></li>
    <li class="card"><img src="images/bleh-puppy.jpg" alt=""></li>
    <li class="card"><img src="images/bleh-tapir.jpg" alt=""></li>
    <li class="card"><img src="images/cat-on-stairs.jpg" alt=""></li>
    <li class="card"><img src="images/chocolate-puppy.jpg" alt=""></li>
    <li class="card"><img src="images/corgisquee.jpg" alt=""></li>
    <li class="card"><img src="images/corns-and-penny.jpg" alt=""></li>
    <li class="card"><img src="images/crazy-otter.jpg" alt=""></li>
    <li class="card"><img src="images/cute-brown-puppy.jpg" alt=""></li>
    <li class="card"><img src="images/dalmatian.jpg" alt=""></li>
    <li class="card"><img src="images/derpy-hedgehog.jpg" alt=""></li>
  </template>
</ul>

This allows me to maintain all the info of my images in HTML (rather than having to add all the sources, alternative text, titles and so on in some JSON blob) and only load the first five when the page loads.

To add the rest, I just use an onload handler, that takes the content of the template and adds it to the parent element.

window.addEventListener('load', function(ev) {
  // check if template is supported
  // browsers without it wouldn't need to
  // do the content shifting
  if ('content' in document.createElement('template')) {
    // get the template
    var t = document.querySelector('template');
    // get its parent element
    var list = t.parentNode;
    // cache the template content
    var contents = t.innerHTML;
    // kill the template
    list.removeChild(t);
    // add the cached content to the parent
    list.innerHTML += contents;
  }
  all = document.body.querySelectorAll('.card').length + 1;
  updatecounter();
});

The difference is pretty significant. Without the template trick the 542 KB transferred in 26 requests take 6.43 seconds on a 3G connection. The onload handler fires after that. With the template, onload fires at 2.08 seconds. Here’s a screenshot of both using Chrome Devtools:

Onload delay with and without template

Template support is pretty great. The only browsers that don’t support it for now are IE and Microsoft Edge. Opera Mini also doesn’t support it, but that’s due to it’s non-client script nature.

Browsers that don’t support template will load all the images and delay the onload handler. But all the others can properly benefit from this. Why not give it a go?

Share on Mastodon (needs instance)

Share on Twitter

My other work: