Do Not Use Gatsby Image Above the Fold
TLDR: Gatsby Image uses JavaScript to complete the image load process. The older Gatsby Image combined with the older PageSpeed Insights tool both show an increased LCP. Since then many improvements have been made. If using the old Gatsby Image this article may help. And is also interesting to see the difference in image types and timings.
Edit 3: PageSpeed Insights seem to have updated the way they view images. This means that the original Gatsby Image, the newer Gatsby Plugin Image, and Base64 are all quick. Interestingly they now see the standard default Img tag as slower. The links are below for you to run the tests in your browser. I used pagespeed.web.dev/report.
Edit 2: Gatsby have released a newer image component called Gatsby Image Plugin, which takes care of most (if not all) of the issues outlined in this article, as well as introducing the new AVIF image type. The above the fold problem is no longer a problem if using this component. I have added an example below to show this.
Edit 1: Since the original publishing of this article, Google has acknowledged the issue and are working on a fix. Blur up image loading should not be seen as detrimental to the users experience, due to a better perceived performance. For more info take a look at this tweet: https://twitter.com/addyosmani/status/1277293541878673411. However, if your bonus is based off the Google Page Speed Score – keep reading.
Gatsby Image is one of the best packages I have used in the Gatsby/Jamstack ecosystem. Super easy to get to work, and does a lot of the hard work in terms of image loading/speed for you. Connect it to the GraphQL image query and away you go.
And then Google released their new Web Vitals.
This knocked all of my 100% speed scores down off the 100 mark, and I couldn’t understand why. Until I gave the Google Web Vitals documentation a read. This is their 2020 goal:
‘The current set for 2020 focuses on three aspects of the user experience—loading, interactivity, and visual stability’.
Makes complete sense. Make the user experience as good as possible. No shaky pages, and a smooth journey. But why the low score? I thought Gatsby was the one tool to get 100% SEO scores every time? Turns out it comes down to the Largest Contentful Paint, or LCP.
‘Largest Contentful Paint (LCP): measures loading performance. To provide a good user experience, LCP should occur within 2.5 seconds of when the page first starts loading.’
Gatsby Image uses JavaScript to manage the image load. This means any image above the fold is not completely loaded until the rest of the site has loaded and the JS has parsed.
I created three different pages as a test to see which way of loading images was the best – Gatsby Image, Standard img/picture tags, or Base64 encoded image. Everything on the each page is exactly the same – apart from how the image is loaded above the fold. I have used webP images where possible, and used Gatsby and GraphQL to process and return the images.
If you want to see what is happening behind the scenes, take a look at the repo: https://github.com/robmarshall/gatsby-image-above-fold-example
Using Gatsby Image above the fold
This screen grab shows the LCP on a page where an image is loaded using the Gatsby Image package above the fold. Although there is the base64 blurred image in frame from the very beginning – Google is not happy with it. They feel that the image must not be changing if you want the LCP timer to stop.
Page where data came from: https://thirsty-lichterman-73c92d.netlify.app/
Using Img/Picture Tag above the fold
Here I have rebuilt the img/picture tag using the image data passed out by the Gatsby GraphQL query. Removed any need for JavaScript and let it load naturally.
Page where data came from: https://thirsty-lichterman-73c92d.netlify.app/alternate/
Using Base64 above the fold
Here I have requested that Gatsby creates a base64 version of the same image shown above. Only the base64 encoded image is used.
Page where data came from: https://thirsty-lichterman-73c92d.netlify.app/base64/
Using Gatsby Plugin-Image above the Fold
This example shows the newer Gatsby Plugin Image, using the Static Image component. It uses the loading="eager"
to ask the browser to render the image as the dom is parsed. An additional bonus would be to remove the fade in animation completely, so there is no additional HTML/CSS to handle this transition. However there seems to be a bug in the current component.
Page where data came from: https://thirsty-lichterman-73c92d.netlify.app/gatsby-plugin-image/
Outcome
It seems that using Base64 images above the fold is the best way to go. This seems to go again every article ever written about base64 images. The rule is usually: if the image file itself is larger than than the base64 string required to make it – host the image on a server. This is due to the base64 string increasing the size of the HTML file making the initial page heavier. Not only this, as the image is attached directly to the HTML it is not cached. This means if the image is used elsewhere on the site it needs to be re-downloaded.
With that in mind, this approach should only be used for the first page of a sales funnel – where you know that speed/SEO matters.
If you would prefer to be able to cache the image – you would still be better off not using Gatsby Image.
I did not use it in this experiment, but Gatsby Image does have a setting to remove the lazy load as well as changing the way the image is loaded. This does not seem to remove the need for JS to complete the loading of the image. To read more about this take a look at the docs: https://www.gatsbyjs.org/packages/gatsby-image/.
It would be great to hear your thoughts on the above. Let me know on Twitter: https://twitter.com/robertmars