How to improve image loading with Gatsby and gatsby-plugin-sanity-image?

9 replies
Last updated: Nov 27, 2020
how do I achieve this same result and avoid this content jankiness (image pushing down content) in Sanity? https://css-tricks.com/do-this-to-improve-image-loading-on-your-website/
I am currently editing
Blog with Gatsby
template but so far dumbfounded on how to solve this with sanity (gatsby-image seems to do it for you). Do I modify in this file here? https://github.com/ajmalafif/afif.dev/blob/develop/web/src/lib/image-url.js
or somehow I can achieve this “lazy-loading” effect by combining both
gatsby-image
and
sanity/image-url
? https://github.com/sanity-io/gatsby-source-sanity#fluid
AI Update

Based on the CSS Tricks article you linked and your question about avoiding content jankiness (images pushing down content) in Sanity with Gatsby, I have a solution for you.

The Modern Solution: Use gatsby-plugin-image

The best way to prevent layout shift with Sanity images in Gatsby is to use gatsby-plugin-image, which automatically handles aspect ratio preservation and prevents content from jumping around as images load.

Here's how to implement it:

import React from 'react'
import {GatsbyImage} from 'gatsby-plugin-image'

const BlogPost = ({data}) => {
  return (
    <article>
      <h1>{data.sanityPost.title}</h1>
      <GatsbyImage 
        image={data.sanityPost.mainImage.asset.gatsbyImageData} 
        alt={data.sanityPost.mainImage.alt}
      />
    </article>
  )
}

export const query = graphql`
  query BlogPostQuery {
    sanityPost {
      title
      mainImage {
        asset {
          gatsbyImageData(
            fit: FILLMAX
            placeholder: BLURRED
          )
        }
        alt
      }
    }
  }
`

Why This Works

  1. Automatic Aspect Ratio Preservation - Sanity's image metadata includes dimensions, so Gatsby calculates the aspect ratio and reserves the correct space before the image loads

  2. Built-in LQIP Support - Sanity automatically generates LQIP (Low Quality Image Placeholder) data for every uploaded image. When you use placeholder: BLURRED, it displays a tiny blurred preview instantly while the full image loads

  3. No Layout Shift - The space is reserved with the correct aspect ratio, preventing the "jank" of content jumping around

Don't Modify image-url.js

You don't need to modify the image-url.js file. Instead, replace manual @sanity/image-url usage with GatsbyImage components throughout your templates. The old approach with gatsby-image and fragments like GatsbySanityImageFluid is deprecated.

If You Must Use Raw URLs

If you need to use @sanity/image-url for some reason, you can query for dimensions and manually set aspect ratios:

import imageUrlBuilder from '@sanity/image-url'

const builder = imageUrlBuilder({projectId: 'abc123', dataset: 'blog'})

const BlogImage = ({image}) => {
  const {width, height} = image.asset.metadata.dimensions
  const aspectRatio = (height / width) * 100
  
  return (
    <div style={{
      position: 'relative',
      paddingBottom: `${aspectRatio}%`,
      overflow: 'hidden'
    }}>
      <img 
        src={builder.image(image).width(800).url()}
        alt={image.alt}
        style={{
          position: 'absolute',
          top: 0,
          left: 0,
          width: '100%',
          height: '100%',
          objectFit: 'cover'
        }}
        loading="lazy"
      />
    </div>
  )
}

However, I strongly recommend using gatsby-plugin-image instead - it handles all of this automatically plus gives you responsive images, lazy loading, and better performance.

Migration Steps for Your Blog Template

Since you're working with the Blog with Gatsby template:

  1. Ensure gatsby-plugin-image is installed (should be included in the template)
  2. Replace any manual imageUrlBuilder usage with GatsbyImage components
  3. Update your GraphQL queries to use gatsbyImageData instead of old fragments
  4. Use placeholder: BLURRED to leverage Sanity's automatic LQIP generation

This gives you the same result as the CSS Tricks article recommends (reserving space with aspect ratios and showing placeholders), but it's all handled automatically by Gatsby and Sanity working together. No manual calculations needed!

it seems from observation and this is anecdotal, seems like Gatsby solution do something like this to avoid the content jump https://css-tricks.com/preventing-content-reflow-from-lazy-loaded-images/
will investigate how can I figure this out for sanity on gatstby
I just published gatsby-plugin-sanity-image to provide an easy way to handle this. Use the
ImageWithPreview
version to avoid the CLS issue.
shout out to
Corey Ward
now I have a solid base to start figuring this jank-free content layout. With
Slow 3G
network on devtools I have
lqip
right away!
kinda looks this with
gatsby-image
from the markup it seems like it does something differently
You can get those thumbnails to scale up and keep your content from jumping around by putting the image in a container sized how you want, then setting the CSS on the image to
display: block; width: 100%
. Unless you are cropping the image, the LQIP should be the same aspect ratio. If you are cropping the image, you can instead set the absolute dimensions on the img element and use
object-fit: cover
on it.
again
Corey Ward
to the rescue! thanks that’s a really good pointer
Corey Ward
is there a way to enable discussion tab on https://github.com/coreyward/gatsby-plugin-sanity-image/ since I encounter difficulties on resizing the
lqip
which I am not sure if it’s a bug (hence i dont think i should create an issue ticket) but I also want to ask how since I tried and failed
figured it out by setting the CSS for
[data-lqip]
and its all worked out now! highly recommend this plugin! Now I know how to make the site jank-free 🥳

Sanity – Build the way you think, not the way your CMS thinks

Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.

Was this answer helpful?