Back to posts

Using Next Image as a full-width background when the URL comes from the CMS

The Next Image component is one of the first things people mention when they advocate for the framework as a big advantage - automatic optimization, responsive sizing, the usual pitch.

Now, here in my Playade project, I'm supposed to use a background picture on a hero section. But how do I do it with the image path coming from CMS data? And more importantly, how do I take advantage of the Next Image optimization if I'm using it as a background-image property in a CSS file, which is what I was doing in the "old days" of web dev?

I know I could have an image set to position: absolute and make it cover the background of a relative section, but that solution feels kinda "hacky" and "dirty". Surely the Next team thought of that scenario. But what is the "proper" way to achieve that effect with Next Image? Not even the social media influencers posting about Next Image knew the answer when I asked them.

Well, it turns out there is a way, which I found out from this leerob YouTube video that just dropped - and in fact, it's not that different from the position: absolute hack, except since it's achieved with attributes, it looks cleaner.

The gist is still "an image layer behind the content", but you don't hand-roll the absolute positioning yourself. You put <Image> inside the section, give the section position: relative (and enough height so the section isn't collapsed), then on the image you use the fill attribute. That makes the image stretch to the parent's box.

One other thing to keep in mind: with fill, you're supposed to pass sizes. Otherwise Next doesn't have a good hint for which responsive width to generate, and you can end up with the wrong optimization behavior. For a full-bleed hero, sizes='100vw' is the usual answer - "this thing is as wide as the viewport".

From the same video / pattern, the other things that make it feel more like a hero photo rather than a tiny compressed thumbnail: quality={100} if you don't want it to look mushy on a big surface, and style={{ objectFit: 'cover' }} (plus objectPosition if you need to adjust the crop). I also threw priority on this one because it's above the fold.

The video also walks through placeholder='blur' when you have something to feed the blur with. I didn't chase that on this hero (yet) - the URL is coming straight from Contentful and I was happy enough getting the layout right first.

1{backgroundImage && (
2 <Image
3 src={`https:${backgroundImage.fields.file.url}`}
4 alt='Julijana i Marina'
5 fill
6 priority
7 sizes='100vw'
8 quality={100}
9 style={{ objectFit: 'cover', objectPosition: '36% 31%' }}
10 />
11)}

So no, you don't get to stuff a CMS URL into background-image in a .css file and still have next/image do its thing. You keep the image in React, let fill + sizes carry the "background" semantics, and live with the fact that under the hood it's still a positioned layer - just one that reads like the framework meant it to be used that way.