Optimising gatsby‑image Even Further

Hero image for Optimising gatsby‑image Even Further. Image by Omar Flores.
Hero image for 'Optimising gatsby‑image Even Further.' Image by Omar Flores.

Although not a direct dropin replacement for an <img/> tag, gatsbyimage is a simple React component which is specifically designed to work with Gatsby's GraphQL queries and native image processing/transformations. It uses these capabilities alongside some very clever imageloading techniques to vastly optimise image loading onsite. No doubt if you are reading this, you are already familiar with both Gatsby and gatsbyimage, but suffice it to say: it is an absolute mustuse for projects developed in Gatsby.

Whilst I won't dive too deeply into how it works (the official documentation is here for a more indepth read), the basic idea is that you use GraphQL to output a set of images and pass it to the component. When the page first loads the component displays a blurred, very lowresolution, inlined Base64 version of the image and then uses Intersection Observer to determine when an image is needed and loads in the higherresolution version, giving that trademark 'blur up' effect as you scroll the page.

Whilst this is incredibly efficient and clever, there are two very loweffort steps that I always take to increase the performance (or in one case perceived performance) yet further.

Photograph of a computer image glitch by Michael Dziedzic on Unsplash.

Only Use as Much Image as You Need

It might seem obvious, but this is one I come across more than anything else when picking up another developer's work. The larger the dimensions of your image, the bigger the file size, and the slower the load. gatsbyimage does some very smart things with the image srcset to help the browser determine which image to load, but this is only as intelligent as the image data fed to it.

The Gatsby Image API provides a set of query parameters that you can use to resize an image right in your GraphQL query. Put bluntly: if you are not using these in your queries, then you are not optimising your images.

Whilst the focus of this article is on improving yet further perceived image load times it is important to note that the default values for these parameters are generally quite low, so setting these may in actual fact increase your file size slightly, but will probably improve the rendering of the image in return.

There are two key parameters I focus on in my projects:

Maxwidth

If you are using a fixed query, then this would simply be width, and could even be combined with height, but I most commonly use fluid queries: my sites are responsive, so the size of space an image takes up onscreen is determined by width rather than by height and often changes if you resize the browser. This is a simple int, in pixels, and defaults to 400, which I expect may well be very low for many people's needs.

If you take away nothing else from this article, take away this: the value you pass here is the maximum physical size of your image, on screen, in pixels. Do not be tempted to double it up to account for retina screens, gatsbyimage already does that for you so you will just end up serving images multiple sizes too large for your visitors.

Quality

This is again a simple int which you can essentially think of as a percentage: 100 is totally lossless compared to the original, whilst at 0 probably won't allow you to identify what the image even contains. By default, this is set to 50 which I personally feel is a little on the low side, especially as a lot of the freelance work I use Gatsby for tends to be fairly imageheavy so I tend to be nearer 80 or even 90. Nevertheless, you can tweak this upwards and downwards until you find a value that works for your content.

All combined together, use your GraphQL query to ensure that the image assets you are passing through to gatsbyimage are already as optimised as possible: the right dimensions, and the right quality.

Your query should look similar to:

image {  childImageSharp {    fluid(maxWidth: 800, quality: 80) {      ...GatsbyImageSharpFluid_withWebp    }  }}
Glitchy and blurry photograph of people standing in front of fireworks on the beach by Atul Vinayak on Unsplash.

Use the Browser's Native Loading Attribute

One of the props gatsbyimage accepts is loading. This is passed straight through to the eventual <img/> element rendered onpage and allows you even further finite control over when an image should actually be loaded by leveraging the browser's builtin loading capability. You can read about it in much more detail on Google's own blog here, even if you aren't using gatsbyimage, you should still be using this on your images!

For the sake of our discussion, the one thing that really surprised me when asking for feedback from clients was that the opinion over whether the blurup effect was desirable or not was split very evenly and generally on the extremes. On one side, some felt it was the coolest feature in the world, whilst others very strongly opposed it: one person even went as far as to say that they would never hire a developer whose website did that!

So, the answer lies in the perceived loading speed of the image: people don't want to see the image blurring into view, they want the image already there and ready to look at by the time they reach it on the page.

Enter loading="eager". By setting the loading prop to eager, you are signalling to the browser that the image should be loaded more urgently, which bypasses any other lazyloading options and ensures that the image loads as soon as is possible.

Your JSX should look something similar to this:

<Img  fluid={image.fluid}  alt="lorem ipsum"  className="lorem__ipsum"  loading="eager"/>

The nice thing about this approach is that it is using the browser's native capabilities rather than relying on JavaScript to determine when an image ought to be loaded. This ensures that everything else pagecritical is still loaded first, but that there is no further delay in loading the images, even if offscreen.

Despite the image not actually loading any more quickly than it might otherwise, they certainly appear to. Using this in conjunction with gatsbyimage means that you get the best of both worlds: images in view will still blur up as they load (something you probably see in the hero image at the top of this article when you first arrived), whilst every image below the fold should already be there by the time you scroll to them.


Categories:

  1. CSS
  2. Development
  3. Front‑End Development
  4. Gatsby
  5. Image Rendering
  6. JavaScript
  7. JSX
  8. Performance
  9. React