DEV Community

Cover image for Enhancing Images on the Web
Fabian
Fabian

Posted on

Enhancing Images on the Web

As a developer, I noticed that I sometimes code:

<img ...>
Enter fullscreen mode Exit fullscreen mode

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 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

Page Weight on HTTP Archive

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

Images: 31.5% for Desktop | 32.5% for Mobile

Images: 31.5% for Desktop | 32.5% for Mobile

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.


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.

<img loading=”lazy" src="...">
Enter fullscreen mode Exit fullscreen mode

https://caniuse.com/#feat=loading-lazy-attr

https://caniuse.com/#feat=loading-lazy-attr

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

webp support https://caniuse.com/#search=webp

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. 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:

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));
Enter fullscreen mode Exit fullscreen mode

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

So how is it possible to fix responsive layout and layout shifts 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🎉

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 <img>.

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 <picture> element via the media attribute and 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🤯)

// 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>
Enter fullscreen mode Exit fullscreen mode

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. 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.

This is where you can find a masonry demo.





Is this the silver bullet? Leave your comment 🤗

Top comments (2)

Collapse
 
pavelloz profile image
Paweł Kowalski • Edited

I personally prefer progressive jpeg than this line-by-line (streaming) approach.

I think "progressive" demos are demonstrating just that: github.com/AnthumChris/fetch-progr...

Collapse
 
fabkrut profile image
Fabian • Edited

I agree. The line-by-line streaming approach is what is browser is doing. More observable on big pictures: NASA Image

My idea with the progress in fetch was to detect the most dominant color and transitioning those over the whole height and width while downloading. I think this is still possible and I am just lazy 😁
This would get rid of the set-up for the preview picture.