How To Make a Hero Image in Next.js
Tags: react, webdev, nextjs, css
Published: 2022-07-24 15:54:48

You may have made a hero image a few times before, but have you done one in Next.js? If you haven't done that, you may find it tricky if you would try. Here I'll guide you how to do that and warn you about the gotchas.

## In This Article

1. [Next.js Image Component](#nextjs-image-component)
1. [Failed Attempts To Create a Hero Image With Next.js](#failed-attempts-to-create-a-hero-image-with-nextjs)
1. [How To Create a Hero Image With Next.js](#how-to-create-a-hero-image-with-nextjs)
1. [Solution Explained](#solution-explained)
1. [Summary](#summary)

![Thor impressed by Hulk hero Banner meme](https://www.perssondennis.com/images/articles/how-to-make-a-hero-image-in-nextjs/thor-impressed-by-hulk-hero-banner.webp)
_Bruce yourself, Hulk is coming_

## Next.js Image Component

Next.js provides a really powerful [Image component](https://nextjs.org/docs/api-reference/next/image) which you definitely should use if you don't have a reason not to. It handles several things for you, some which are enabled by default and some which you have to specify yourself. Some examples of what the Image component can do are:

- Automatically resize images for you. No need to manually generate images of different sizes to use in a picture element with a srcset. It supports [several type of layouts](https://nextjs.org/docs/api-reference/next/image#layout). Unfortunately, it isn't very easy to understand from the documentation when to use which layout.
- Lazy load images. Images are fetched firstly when they are closed to being scrolled into view. If you need to opt out of this behavior, you can specify the [prioritize property](https://nextjs.org/docs/api-reference/next/image#priority).
- It lets you [optimize](https://nextjs.org/docs/api-reference/next/image#sizes) image [sizes](https://nextjs.org/docs/api-reference/next/image#image-sizes) and [quality](https://nextjs.org/docs/api-reference/next/image#quality) in different ways.
- Allows you to [blur images](https://nextjs.org/docs/api-reference/next/image#placeholder) by providing a temporary blur-image. If you want a single-colored blurred background, you can generate a base64 encoded one [here](https://png-pixel.com/).

```react
<Image
    blurDataURL="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mPkso6pBwACGgEie2Im0gAAAABJRU5ErkJggg=="
    placeholder="blur"s
    src={memeUrl}
    layout="fill"
    alt="Programming meme"
/>
```

_Pass a base64 image to blurDataURL to use it as a blur placeholder_

To see blurred images in action, head over to the [memes page at my website](https://www.perssondennis.com/memes) and scroll down. Next.js handles the blurring and lazy loading automatically.

## Failed Attempts To Create a Hero Image With Next.js

Trying to create a hero image with Next.js can be a troublesome process. As I mentioned above, you should use Next.js built-in Image component if you don't have a reason not to.

In a first attempt to create a hero image, you may think you can set the width of the Image component to 100%. Unfortunately, that is not possible with remote images, Next.js don't support that. You'll end up with a 100px wide image instead.

A second try could be to avoid specifying width for the Image component in hope for that it would fill the parent element. Doing that will result in an Unhandled Runtime Error.

    "Error: Image with src SOURCE must use "width" and "height" properties or "layout='fill'" property."

![Image with src SOURCE must use "width" and "height" properties error](https://www.perssondennis.com/images/articles/how-to-make-a-hero-image-in-nextjs/nextjs-image-with-src-source-must-use-width-and-height-properties.webp)
_Next.js Image component requires a width and height, or a fill layout_

The error Next.js outputs is quite clear. You are required to set both a width and a height on the Image component, unless you provide the _fill_ value to the layout property. You do exactly what Next.js suggests since you are a law-abiding citizen, or maybe because you have no better ideas to try.

Using the layout property removes the error, but your hero image now fills the whole viewport instead of the div that wraps it. Perfect... You start realizing that you will be late to grandma's dinner party tonight.

Being pretty great at hacking CSS, you play around with the element inspector in the browser a bit. You don't really get anywhere and neither Stack Overflow or Next.js documentation is to any help, and you don't find a tutorial for it. Maybe it's best to use a native image element rather than the Image component Next.js provides?

![Grandma-invites-rabbit-meme](https://www.perssondennis.com/images/articles/how-to-make-a-hero-image-in-nextjs/grandma-dinner-party-meme.webp)
_An apology to all vegans, there will be no food for you. And for the sharp joke, I know it isn't bunny..._

## How To Create a Hero Image With Next.js

I'm happy to announce that there is an easy way to fix it. The key to success is to use _position: relative_ on a parent element. I would suggest to do four things.

1. Add a hero wrapper element with _position: relative_ and an appropriate _width_ and _height_.
1. Add a Next.js Image component with the _layout_ property set to _fill_.
1. Wrap the Image component in a div with _z-index: -1_.
1. Add whatever hero content you want in a relative positioned div in the hero wrapper. Place your hero content in that div.

The complete solution would look like this.

```react
// Header component.
import Image from "next/image";
import styles from "../header.module.css";

const { heroContent, heroWrapper, imageWrapper } = styles;

const IMAGE_URL =
  "https://www.perssondennis.com/images/articles/how-to-make-a-hero-image-in-nextjs/perfect-avocado.webp";

export default () => {
  return (
    <div className={heroWrapper}>
      <div className={imageWrapper}>
        <Image
          priority
          src={IMAGE_URL}
          layout="fill"
          objectFit="cover"
          objectPosition="center"
          alt="hero image example"
        />
      </div>

      <div className={heroContent}>
        <h1>Hero Image</h1>
        <p>Next.js hero image example.</p>
      </div>
    </div>
  );
};

```

```css
// header.module.css

// step 1.
.heroWrapper {
  position: relative;
  width: 100vw;
  height: 50vh;
}

// step 3.
.imageWrapper {
  z-index: -1;
}

// step 4.
.heroContent {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
}
```

![Next.js hero image example](https://www.perssondennis.com/images/articles/how-to-make-a-hero-image-in-nextjs/nextjs-hero-image-example.png)
_This is what it would look like using the hero image on a page_

## Solution Explained

So, what did we do there? In step _1._ we added a relative position to the hero wrapper. That's the secret to success in this case. Next.js will set an _absolute_ position on its image when you set the _layout_ property to _fill_ in step _2._.

```css
// step 1.
.heroWrapper {
  position: relative;
  width: 100vw;
  height: 50vh;
}
```

```html
<div className="{imageWrapper}">
  <image
    priority
    src="{IMAGE_URL}"
    layout="fill"
    objectFit="cover"
    objectPosition="center"
    alt="hero image example"
  />
</div>
```

In CSS, absolute positioned elements are absolute relative to their [closest parent that is explicitly positioned](https://www.w3schools.com/cssref/pr_class_position.asp). By setting the hero wrapper's position to relative, the absolute positioned image within it will grow to be just as large as the hero wrapper becomes.

The hero wrapper will in turn be as large as the content you add to it in step _4._. Note that the hero image's width and height does not contribute to the hero wrapper's width and height since the image has an absolute position.

If you would remove the relative position from the hero wrapper, you would see that the image instead grows to be as large as the viewport, because no parent or grandparent has a position specified.

In step _3._, we wrapped the hero image in a div (_imageWrapper_) with z-index set to _-1_, and in step 4 we added a relative positioned div (_heroContent_) as a sibling to the image wrapper. That is just to ensure that other components will show on top of the hero image.

```css
// step 3.
.imageWrapper {
  z-index: -1;
}

// step 4.
.heroContent {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
}
```

We do now have what we need to implement a hero image with the Next.js Image component. You can fill it with whatever content you want, personally I prefer centered content, which is most easily done with flex column and a centered _align-items_ property!

## Summary

- Always use Next.js Image component if you don't have a reason not to do it.
- If you want to create a hero image with Next.js image component, wrap the hero image and its content in a _relative_ positioned div and set the image's _layout_ property to _fill_.
- Wrap the hero image in a div with a _z-index_ of _-1_ to make it show underneath the content in the hero section.
- Create a div below the image wrapper and let it have a _relative_ position.

{% embed https://dev.to/perssondennis %}