Enhancing Images on the Web
Tags: javascript, css, html, webdev
Published: 2020-06-30 21:23:20

As a developer, I noticed that I sometimes code:

```html
<img ...>
```

However, there are some points to consider when working with images:
* Lazy Loading
* Responsiveness
* Avoiding Layout Shifts
* File Size
* Intial fast load
* Accessibility
* Art Direction

Which leads to the question — is there a way to combine as many points of them as possible with one approach? **Luckily there is**.

###**The importance of images**
First, let’s emphasize why we should care about this. On [HTTP Archive](https://httparchive.org/reports/page-weight?view=grid) it is noticable that 47.3% of the total sent KB per page are from images on desktop in 2020 (47.9% on mobile).

![Page Weight on HTTP Archive](https://dev-to-uploads.s3.amazonaws.com/i/sc6rm24g2o51zx5ubwqp.png)
<figcaption>Page Weight on HTTP Archive</figcaption>

Because the summed bytes do not equal the *Total Kilobytes*, I created the following chart.

![Images: 31.5% for Desktop | 32.5% for Mobile](https://dev-to-uploads.s3.amazonaws.com/i/la4hp4oo5hd0maleuf0w.png)
<figcaption>Images: 31.5% for Desktop | 32.5% for Mobile</figcaption>

Altough videos are the most significant ressources considering the size, images are on the next place and from a developers perspective, almost all applications are using images which is not true for videos.
<br>
Another reason for improving images is to make yourself and other people happy browsing on the web. The internet connection might be weak or the mobile data plan might be throttled. Both causes lead to long waiting times, which are definitely unwanted😔.


##**The approach**
Native lazy loading is supported in all modern browsers beside Safari (support is in the *Experimental Phase*). It can be added via an attribute on the element.

```html
<img loading=”lazy" src="...">
```

![https://caniuse.com/#feat=loading-lazy-attr](https://dev-to-uploads.s3.amazonaws.com/i/gcdm37tuyyci0n7l6ahx.PNG)
<figcaption><a href="https://caniuse.com/#feat=loading-lazy-attr">https://caniuse.com/#feat=loading-lazy-attr</a></figcaption>

Alternatively it is possible to use a library which polyfills this functionality. Beside lazy loading to reduce the initial payload, the images could be optimized. However, this is something off the web which would contain reducing quality, reducing the dimensions width and height and transforming the image to better types such as *webp* or *AVIF*™(flagged support in Firefox).

![webp support https://caniuse.com/#search=webp](https://dev-to-uploads.s3.amazonaws.com/i/zer8e3x6en54h1bwc6wo.PNG)
<figcaption>webp support <a href="https://caniuse.com/#search=webp">https://caniuse.com/#search=webp</a></figcaption>

**Progressive Image Loading** — a way to display a low quality preview image and loading the high quality picture at the same time, would also be a great way to save bytes for the intital load (like on medium). While there are libraries for this, I tried to do this without altering the HTML and display the image simultaneously to the request via *Streams*. [Example of fetch progress here](https://fetch-progress.anthum.com/sw-basic/). Sadly, this did not work. Even though the browser was able to display an halfway received image, the transformed Uint8Array could not resolve to an image. Here is the used code to transform the array:

```javascript
function createImageFromArrayBuffer(type, arrayBuffer) {
 const base64String = 
   btoa(String.fromCharCode(...new  Uint8Array(arrayBuffer)));
 const image = new Image()
 image.src = `data:${type}base64,${base64String}`;
 return image;
}
document.body.append(createImage("image/jpeg", arrayBuffer));
```

We will come back to Progressive Image Loading at a later state.
<br>

So how is it possible to fix responsive layout and [layout shifts](https://twitter.com/addyosmani/status/1276779799198007301) at the same time? Both approaches require information about width and height — in HTML and CSS. While setting it in HTML seems like an old fashioned way, it is actually helpful for the browser since December 2019 (Chrome and Firefox). And it will stay responsive as long as the CSS remains. Awesome🎉
<br>

Now, only accessibility, art direction and intial fast load remain open. From my perspective, there is not much to do for accessibility beside adding an alt attribute to the *&lt;img&gt;*.
<br>

**Art Direction** — means that an image might be cropped, exchanged etc. depending on device size, device resolution, dpi, orientation and more. This is easily achievable with the [&lt;picture&gt;](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/picture) element via the media attribute and *<source>* subelements. Those subelements can also be used to let the browser choose the best image type and to change to a higher resolution picture, when needed. (This works with lazy load🤯)

```html
// type
<picture>
  <source srcset="logo2x.webp" type="image/webp" media="(min-width:
    601px)">
  <source srcset="logo1x.webp" type="image/webp" media="(max-width:
    600px)">
  <img loading="lazy" src="logo.jpg" alt="logo" height="320" 
    width="320">
</picture>// srcset
<picture>
  <source srcset="logo-768.png 768w, logo-768-1.5x.png 1.5x">
  <source srcset="logo-480.png, logo-480-2x.png 2x">
  <img loading="lazy" src="logo-320.png" alt="logo" height="320" 
    width="320">
</picture>
```

Which combines almost all of our best practices. That is where progressive loading for the intial fast load comes in. Because it is not natively supported, [I created a library](https://github.com/Krutsch/progressive-picture). All there is to do is adding data-src attributes for the high quality picture and putting the URI of the low quality picture in the srcset and src. It will even change the to the next picture’s width and height attributes, however, it would be probably preferable if these stay the same.
<br>

[This is where you can find a masonry demo.](https://lazy-load-picture.netlify.app/masonry.html)

<br>
<br>
Is this the *silver bullet*? Leave your comment 🤗