Intangible images

Where are my images?

Please, no delay

Web images are an endless challenge: we want them wide, beautiful, we want their colors, their evocation power, but in no case their slowness. Evidently images have to be optimised to be as light as possible. 11tyTips uses the outstanding Compress-Or-Die site Every front-end developer should visit this site not only for the impressive compression engine proposed by Christoph Erdmann but also for a thorough understanding of the JPEG format to lighten and transform all images for a maximum speed gain. Nevertheless, 11tyTips goes further and enforces an on-demand image loading paradigm: any image is loaded only when the site visitor does want to open the Pandora box this is my personal approach to the lazy loading pattern, both lighter and simpler to implement than the usual Observer pattern !

To implement this pattern, the trick is to hide by default all images that do not need to be displayed inconditionnaly therefore any image that is a substantial part of the site page (logo, hero, etc.) is not concerned by this on-demand pattern , and unhide them, one by one, at a later time, when a specific action is triggered by the visitor. That specific action is simply the opening of an inline note, tailored for the image case, as in the following note Adam de Coster


{% _note_img %}
![Adam de Coster][1PX]{data-src="{{U_o.url_s}}assets/media/Adam_de_Coster_gray.jpg" data-size="150"}
{% end_note_img %}

[comment]: # (======== Links ========)
[1PX]: {{U_o.url_s}}assets/media/1px.jpg "OnePixel"

The _note_img shortcode has two parts:

As soon as the site visitor clicks the note index for the first time, the image is loaded. This is not an automatic displaying but a manual one: There is an image here, do you want to see it? If you do, here it is! Of course, if the image has a big size and the network flow is slow, the image will load slowly. Nevertheless, I think the user experience is much better having an overall very fast page loading and a potentially slow image loading, because this is a well known case, and, moreover, there is no need for any blurring or degraded image which only accentuate the waiting perception and finally slow down even more the genuine image display.

Resize à la carte

For the sake of convinience, specific sizes can be specified for each image in the Markdown source, for instance 50%: Adam de Coster
The data-size attribute takes either a unique value it will be applied to the width of the image, the height beeing supplied by the browser, keeping the image ratio :


or two values separated by a space character: applied to the width then the height of the image :

data-size=“200 200”

Since size values are converted in a style attribute added to the image HTML tag, any compliant CSS value can be used: percentage, rem, etc. Adam de Coster


When no size is added to the inline attribute, by default the image width is 100% of the page width and fills the whole available space of its container: if its intrisinc size is less that this one it scales up! . The _note_img shortcode also accept an Array argument to put a legend each slot of this Array is a new line of the legend under the image displayed Adam de Coster
Adam de Coster
Young women holding a distaff

{% _note_img [ 'Adam de Coster', 'Young women holding a distaff' ] %}

A 1px default

Because a true image declaration is needed by the Markdown processor, a one pixel sized image data URI see this base64 png pixel generator is systematically used as a placeholder: it’s very light and 11tyTips has a CSS rule to prevent it to be displayed anyway. And it can be inserted at the end of the Markdown file like it is here, with the an helper function:


[comment]: # (======== Links ========)
[1PX]: {{ F_o.img1px__s() }} "A young woman holding a distaff before a lit candle"

And here is the final code produced:


<ins data--="note_img">
  <span data--="note_content">
    <em class="note_link_a">
      <a class="note_link"
         onclick="loadColorImg__v( this, 'gray', )"> ⤵</a>
    <img src="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs="
         alt="Adam de Coster"
         title="A young woman holding a distaff before a lit candle"
         data-src="{{ U_o.url_s }}assets/media/Adam_de_Coster_gray.jpg"
    <em class="note_img_title">Adam de Coster [1586-1643]</em><br>
    <b class="note_img_subtitle">Young women holding a distaff before a lit candle</b>

Further image optimisation and control

When images displayed using the on-demand loading mechanism described in this tip are an important matter for the site content i.e. images are a substantial part of the content, not just an illustration to decorate the text content ; when image compression must preserve a high rendering quality; the image size can still be heavy, more than a few hundreds of kilobytes. A useful technique is to propose, at first, a meaningful presentation of the image in grayscale instead of full color! Actually, grayscale images, eliminating the less meaningful part of the image data: color, and retaining only the most important one: luminosity, are so useful to the sensory perception that, in many cases, they are the most important step of the content understanding.

As a consequence, 11tyTips can fire a dual step loading mechanism: first, a grayscale image then, only if needed if the site visitor does want it: in the following example, by clicking the button above the image , second, the full size colored image, which replaces the first one Adam de Coster
Adam de Coster [1586-1643]
Young women holding a distaff before a lit candle

Identification and legend

Most of the time, the image tag title attribute an its factotum the alt attribute is enough regarding image identification. But sometimes it can be necessary to display more information for instance a title, a place, a credit, etc. : this is the purpose of the legend Array mentioned above. But some reactivity can be necessary too. This is the purpose of another shortcode, named note_link: this is an Array of strings, each one enclosing a function name with its dedicated symbol and arguments if the function has arguments .

{% note_link [ 'loadColorImg__v, ⤵, gray, color' ] %}

Each slot of this Array yields a link, displaying the function symbol, which triggers the function itself. In the previous image note, the function loadColorImg__v loads the heavy full colored image coming to replace the much lighter gray one initialy loaded, which acts as an image preview Light grayscale image (500 x 720 pixels): 18 698 bytes
Heavy full color image (1388 x 2000 pixels): 158 852 bytes
Ratio is 0.11
This ratio could even be much less using a smaller grayscale image, if the aim were to just have an image preview, instead of a gray image to study contrasts, luminosity, etc.