AboutArticlesGame

How To Make a Hero Image in Next.js

Cover Image for How To Make a Hero Image in Next.js
Dennis Persson
Dennis Persson

URL copied to clipboard

6 minutes reading

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
  2. Failed Attempts To Create a Hero Image With Next.js
  3. How To Create a Hero Image With Next.js
  4. Solution Explained
  5. Summary

Thor impressed by Hulk hero Banner meme Bruce yourself, Hulk is coming

Next.js Image Component

Next.js provides a really powerful Image component 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. 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.
  • It lets you optimize image sizes and quality in different ways.
  • Allows you to blur images by providing a temporary blur-image. If you want a single-colored blurred background, you can generate a base64 encoded one on png-pixel.
<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 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 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 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.
  2. Add a Next.js Image component with the layout property set to fill.
  3. Wrap the Image component in a div with z-index: -1.
  4. 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.

// 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>
  );
};

/* 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 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..

/* step 1 */
.heroWrapper {
  position: relative;
  width: 100vw;
  height: 50vh;
}
<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. 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.

/* 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.

URL copied to clipboard

Dennis Persson

Knowledge Should Be Free

I'm doing this for free because I like to contribute to the world. Knowledge should be free and available to everyone. Still, we all need to make a living somehow, and running this blog takes time and effort. When I find content I value, I support those creators so they can keep doing their amazing work. If you enjoy what I'm sharing here, consider buying me a coffee. It doesn't have to cost more than a coffee!

Buy Me A Coffee

Related Articles

Cover Image for Write SOLID React Hooks

Write SOLID React Hooks

20 minutes readingArchitecture | Frontend | JavaScript | React

SOLID is one of the more commonly used design patterns. Each React article about SOLID presents the model in slightly different ways, some applies it on components, other on TypeScript, but very few of them are applying the principles to hooks

Cover Image for Answers to Common Next.js Questions

Answers to Common Next.js Questions

10 minutes readingFrontend | JavaScript | Next.js

Answers to common Next.js questions such as how Server Components work and how to read params in components

Cover Image for 33 Christmas Animations to Easily Add to Your Website

33 Christmas Animations to Easily Add to Your Website

3 minutes readingFrontend | UI

33 Christmas animation and interactive art which easily can be added you your website. Most of them are CSS only, others requires a small amount of JavaScript

Cover Image for React Hook: useElementDimensions

React Hook: useElementDimensions

9 minutes readingFrontend | Hooks | JavaScript | React

React hook useElementDimensions measures height, width and position of a node or element. It updates the dimensions on resize and scroll events

Browse articles