Progressive image loading with Gatsby
Tags: gatsby, javascript, jamstack, webdev
Published: 2021-03-12 22:13:08

# Images on web pages
If you think about a classic/typical website there are some components that surely you imagine like the navbar and the hero.
The hero component typically has a large image that could impacts on the website performances (see [Google Web Vitals](https://web.dev/vitals/)).

## GatsbyJS
[GatsbyJS](https://www.gatsbyjs.com/) is one of the most famous static site generator that belongs to the [JAMStack movement](https://jamstack.org/).
It has many plugins (to do almost anything) and one of the most used is the `gatsby-image` plugin that shipped great performances to handle images, specially when used in combination with `gatsby-plugin-sharp`.
As GatsbyJS reached the [3rd version](https://www.gatsbyjs.com/docs/reference/release-notes/v3.0/), they released a new plugin for images: `gatsby-plugin-image`.
We will not talk about these changes in this post since my intentions is to show only **how Gatsby can automatically handle images preloading** and **how it's powerful**.


# Gatsby website configuration
The new `gatsby-plugin-image` used in combination with the `gatsby-plugin-sharp` can be really really powerful.
The only thing a website programmer or a content creator should think about is: *upload an high quality image prior to the extension and the size*.
The sharp plugin can be configured to automatically generate new file extensions that will be handled by the `gatsby-plugin-image`. Doing this, the client will use the best extension you provide and it will have great performances.

## Image placeholders
Placeholders are important for two reasons:
1. score on tools like Google Lighthouse
2. UX

The plugin already ship the first point as:
> To ensure that the layout does not jump around, a placeholder is displayed before the image loads

By default the placeholder is set to DOMINANT_COLOR but to have a better UX we should need to change it.

Now the question is: what it is the best choice?
There are few options: DOMINANT_COLOR, BLURRED, TRACED_SVG and NONE.

#### NONE
In my opinion you should not display NONE as placeholder because it could lead to have large empty spaces before the image is loaded. These spaces could be confusing for an user as at first sight seems that the layout is broken.

#### DOMINANT_COLOR
The default choice is too easy and generates a flat colored area that is not able to communicate what the image will contains.
NOTE: this is a personal opinion, maybe you could love this setting.

#### BLURRED
It shows the whole image but it is "animated" from blurred to sharpened, gradually. I like this solution because is like focusing a subject with a camera.

##### TRACED_SVG
It is the most complicated solution but is the one I really love because it generates a sequence of images that lead the user to think that there is a painter that is painting in front of the user: starting from the main shapes of the image.

### How to choose
How I should choose between BLURRED and TRACED_SVG?
Even if I put some personal opinions in the previous section, what I really need is rational decision: **based on data**.

So, I produced a local build of the website and performed some checks with the Lighthouse tab of Google Chrome dev tools.
```sh
gatsby build && gatsby serve
```
I will report only the *performance* score as the image loading doesn't impact *accessibility*, *best practice* or *SEO* scores.

#### Results
BLURRED on mobile: **82**
TRACED_SVG on mobile: **77**
BLURRED on desktop: **99**
TRACED_SVG on desktop: **98**

Note: each score is calculated as the mean of 10 tests.
Note 2: GatsbyJS serve without HTTP/2 that lowers the score
Note 3: the website is a work in progress and there are other things to touch to have better performances

And the winner is... **BLURRED**!
It's clear that it has better performances on mobile than the other option.

### gatsby-conf.js
```js
module.exports = {
    plugins: [
        // ... some plugins before
        {
            resolve: `gatsby-plugin-sharp`,
            options: {
                defaults: {
                    formats: [
                        `auto`,
                        `webp`,
                        `avif`,
                    ],
                    quality: 100,
                    placeholder: "blurred",
                },
            },
        },
        // ... some plugins after
    ],
}
```
I choose "blurred" as placeholder but I also explicitly choose to generate AVIF and WEBP images to take advantage of the best possible compression available for the web.

### Bonus
All images in the website will have the BLURRED placeholder by default but it can be overwritten if you need.
This is the case of the logo in the navbar: since the image contains only a bird with a background I have chosen to use a TRACED_SVG placeholder. In my opinion this solution is more artistic.

## The result
Navbar logo: TRACED_SVG
Main image: BLURRED
{% youtube qdu1izINIhs  %}