Contents

Image Optimize for web

Here is a walkthrough of steps I took to optimize images for my blog synille.se.

First of, there are some good tips to follow:

  • Use JPG for photoimages. PNG for graphics with large flat-color areas. SVG for icons if you have.
  • File-names: Short, small letters, no symbols or sign, and descriptive for SEO.
  • Max-width: 2500px for full-width images. 800px for “in article” images.
  • Never have an image over 500kb.

Imagehandling with Imagemagick

For handling the image sizes and quality I used the tool imagemagick. To install it on mac you can use brew:

brew install imagemagick

To resize images:

convert my-image.jpg -resize 800x800 output.jpg

To change image quality for JPG:

convert my-image.jpg -quality 80 output.jpg

Check size differences

du -sh my-image.jpg output.jpg

To convert between filetypes you only need to change the extension:

f=my-image.jpg
convert $f ${f%.jpg}.png

Example, converting all png in folder to jpg:

for f in *.png; do 
  convert $f ${f%.png}.jpg
  rm $f
done

First contentful paint

If the webpage is long and has many images it will delay the time it takes for the browser to render it. The browser will try to fetch all images while trying to render the page. It might take seconds for your user to see a first contentful paint.

Use lighthouse (or pagespeed) to see insights of the performance of your webpage.

Now, everything in a large page is not equally important to render when a visitors first tries to load the page. As the user starts at the top of the page it is more important to load the header and banner. The images within the article are further down and aren’t necessary to load first. As it will take the user some time to scroll down to see them.

Native lazy loading

The easiest trick is to use lazy-loading, which is supported by most browsers, except for iOS safari. You only have to add loading="lazy" to the image-tag:

<img src="my-image.jpg" loading="lazy" />

The downside is that you can’t set an offset on how soon the image will start loading. The default is that it loads as soon as it is within the window.

This creates a laggy feel to it if you scroll down quickly. Specially if you don’t have a min-height set so that the image pushes down the content after it is being loaded.

JS Lazy loading

There are JS libraries that allow you to set an offset of when to start loading the image. A downside is that you need to have an JS library… And it will constantly check the scrolling and compare to all your lazy-components to determine if it should load or not. I don’t see it as a optimal solution. As it requires more JS to be sent to the browser, and it uses unneccesary runtime calculations while scrolling.

Defer

A better solution is to defer the images using a small JS script. First hide the image-URL in an alternative attribute on the img. Such as:

<img data-src="my-image.jpg" />

This will ensure that the browser doesn’t try to load the image.

At the bottom of the page you can add this script:

function init_defer_images() {
  Array.from(document.getElementsByTagName('img')).forEach(imgTag => {
    if (imgTag.getAttribute('data-src')) {
      imgTag.setAttribute('src', imgTag.getAttribute('data-src'));
    }
  });
}
window.onload = init_defer_images;

The browser tries to render in sequence. So by putting this script at the end of the page it will be executed last and give the header/banner time to render before. Once the script has updated the src-attribute in the DOM it will trigger the browser to fetch the images and rerender the img-tags.

All images that had a data-src-attribute will load as soon as the visitor enters the webpage, without waiting for scrolling, but not be loaded until everything else is loaded. Mission success.