Gatsby-image: provide the right image size to different resolution

Viewed 3339

I am struggling with Gatsby-image to provide the right image size to different resolution. I have an image of size 1920x367 (width x height) and the issue is visible when window size is small (mobile for example) because gatsy-image is using an image of 490x92 to cover a container of 437x354.

Here you can see the image when window size is big. Here when window size is low.

GraphQL query:

configHowWeWork: file(relativePath: { eq: "howwework/howwework-header.jpg" }) {
    childImageSharp {
        fluid(maxWidth: 1920, maxHeight: 367) {
            ...GatsbyImageSharpFluid_withWebp
        }
    }
}

Gatsby-image:

<div className="intro intro-page intro-container">
    {configHowWeWork.childImageSharp.fluid && (
        <Img
            className="intro-background"
            fluid={configHowWeWork.childImageSharp.fluid}
            alt="alt"
        />
    )}
</div>

Relevant CSS:

.intro-container {
    position: relative;
}

.intro-background {
    position: absolute!important;
    height: 100%;
    width: 100%;
    margin: 0;
    padding: 0;
    left: 0;
    top: 0;
    z-index: 0;
    overflow: hidden;
}

Question: How can I avoid to request an image of size 490x92 (same initial aspect ratio) and instead provide one that can fill up 437x354 (cropping or clipping is what I want, but without zooming in) without streching height.

What I already tried:

  1. I tried to use FILL as fit in gatsby query to overcome aspect ratio constraint, but it did not the trick.
  2. Using presentationSize.

Thanks for you answer.

EDIT: THe only one solution found is to create a square image with dimension max(width, height), but in my case is always width. In this way I achieve good quality with low and high resolution (mobile and desktop, for example), but I am wasting too much resource:

  • With a desktop resolution image generated is 1920x1920, but container dimension is 1920x367.
  • With a mobile resolution is not so unbalanced, but still bigger the necessary with height.

I am sure I am missing something because could not be so difficult to just create a responsive wide hero image.

EDIT 2: I can not get why image quality is good if I switch to mobile resolution with Responsive Design Mode in Firefox, but quality is not good if I use a resolution comparable to previous mobile but without Responsive Design Mode.

2 Answers

I overcome issue with 3 images and art direction, I am no able to do better than that.

First, query images:

headerLarge: file(relativePath: { eq: "image-L.jpg" }) {
    childImageSharp {
        fluid(maxWidth: 1920, webpQuality: 100) {
            ...GatsbyImageSharpFluid_withWebp
            ...GatsbyImageSharpFluidLimitPresentationSize
        }
    }
}
headerMedium: file(relativePath: { eq: "image-M.jpg" }) {
    childImageSharp {
        fluid(maxWidth: 900, webpQuality: 100) {
            ...GatsbyImageSharpFluid_withWebp
            ...GatsbyImageSharpFluidLimitPresentationSize
        }
    }
}
headerSmall: file(relativePath: { eq: "image-S.jpg" }) {
    childImageSharp {
        fluid(maxWidth: 500, webpQuality: 100) {
            ...GatsbyImageSharpFluid_withWebp
            ...GatsbyImageSharpFluidLimitPresentationSize
        }
    }
}

Create sources array:

const sourcesImage = [
    {
        ...headerSmall.childImageSharp.fluid,
        media: '(max-width: 500px)',
    },
    {
        ...headerMedium.childImageSharp.fluid,
        media: '(max-width: 900px)',
    },
    {
        ...headerLarge.childImageSharp.fluid,
        media: '(max-width: 3840px)',
    },
];

Use sources with gatsby-image:

<Img
    fluid={sources}
/>

Fluid images in Gatsby stretches across the container (e.g: for a container whose max width is 800px, the automatic sizes would be: 200px, 400px, 800px, 1200px and 1600px). If you want more control over which sizes are output you can use the srcSetBreakpoints parameter. Applied to your code:

configHowWeWork: file(relativePath: { eq: "howwework/howwework-header.jpg" }) {
    childImageSharp {
        fluid(maxWidth: 1920, srcSetBreakpoints: [ 400, 600, 960, 1280, 1920 ]) {
            ...GatsbyImageSharpFluid_withWebp
        }
    }
}

As you can see srcSetBreakpoints is an array of integers with your custom values. This will provide a srcSet to your image with the desired sizes.

You can play with them to check which ones fit your requirements. In addition, I would remove the maxHeight parameter since it may cause you a limitation query because it restricts the aspect ratio of your image in small sizes, it's automatically calculated using the maxWidth provided.

Another hack that may help you is to change CSS object-fit to contain property in some resolutions to fit 100% of the container.

References/Interesting readings:

Related