reactjsgatsbypagespeedpagespeed-insightsgatsby-image

Largest contentful paint is one big gatsby-background-image and very slow


For those stumbling on this question wondering how to improve their lighthouse score in general, I posted an answer on this topic on another question with lots of general tips.


I'm running PageSpeed insights and my biggest problem is the largest contentful paint, at about 8-10 seconds. Below they list my largest contentful paint element

Largest Contentful Paint element 1 element found
This is the largest contentful element painted within the viewport. Learn More
Element

This is the a paragraph that appears above here    
<section class="mainBgImage gbi--716926567-eDXcajFRMpQ2F1s7wNgLk1" style="background-position:center top;background-repeat:no-repeat;background-size:cover;position:relative;opacity:0.99" role="img">

This element is an image that spans my whole website in the background. It was originally a 1.2 MB png that i load using ...GatsbyImageSharpFluid_withWebp_noBase64 with a maxWidth of 1950.

This is the code for how I render it

    import BackgroundImage from 'gatsby-background-image';

    ...

      <BackgroundImage
        Tag="section"
        role="img"
        className='mainBgImage'
        fadeIn={false}
        // style={{objectFit: 'contain',  width: '100%' }}
        style={{
          opacity: 0.03,
          backgroundPosition: "center top",
          
        }}
        fluid={wheatImgProps}
      >
          {children}
      </BackgroundImage>

And this is the static graphql query

    const data = useStaticQuery(graphql
        `query LayoutQuery {
          wheatImg: file(
            extension: {regex: "/(jpg)|(jpeg)|(png)/"},
            name: {eq: "wheat-background"}
          ) {
            childImageSharp {
              fluid(maxWidth: 1950) {
                ...GatsbyImageSharpFluid_withWebp_noBase64
              }
            }
          }
        }
        `
      )


Solution

  • Turns out the solution was to split my background image into 2. One for "above the fold"(Whats visible without scrolling) and one for "below the fold". I also found this image compressor website to be one of the most helpful and straight forward when it came to reducing my file size.

    I then created an absolutely positioned div which looked like

    const BGImg = ({img, className}:{img:FluidObject, className?:string}) => (
        <Img
            Tag="section"
            className={className}
            durationFadeIn={250}
              
            style={{
                opacity: 0.03,
                minWidth:"100%",
                objectFit: 'cover',
                objectPosition: "center top",
            }}
            fluid={img}
        />
    )
    
    ...
    
    <div id='layout'>
        <div id='bgImageContainer'>
            <BGImg img={above_the_fold_bg} />
            <BGImg img={below_the_fold_bg}  />
        </div>
    ...
    

    with styling that looked like

    #bgImageContainer{
        position: absolute;
        z-index: -999;
        min-width:100%;
        min-height:100%;
        display:flex;
        flex-direction: column;
        justify-content: flex-end;
        align-self: stretch;
    }
    
    #layout{
        overflow: hidden;
        position: relative;
    }