ICW
ICW

Reputation: 5789

Next.JS Image `layout='fill'` is broken

When using the Next.js image component, the docs claim that: "When fill, the image will stretch both width and height to the dimensions of the parent element, usually paired with object-fit."

However, this is not what's happening. What it actually does is fill the image to take up the entire screen in a fixed position that doesn't respect scrolling. I've tried each object-fit value possible for the img and none has worked.

To reproduce, make a new next project and put an image in your public folder. Do this:

export default function Home() {
  return (
    <div>
      <div style={{width: '100px', height: '100px'}}>
        <Image src={"/i.png"} layout='fill'/>
      </div>
    </div>
  )
}

Image will take up the entire screen. You can try styling the Image component but I haven't found a way to make it work.

Does anyone know how to fix this, or why it's happening?

Upvotes: 51

Views: 74046

Answers (5)

lodey
lodey

Reputation: 304

This solved my issue, I provide some style to my parent div and it solved

<div className='relative w-[165px] h-[32px] lg:w-[195px] lg:h-[40px]'>
      <Image src='path' alt='logo' fill className='h-full w-full object-contain'/>
    </div>

since while using fill, next js Image consider itself as absolute position so we need to wrapped that by parent component which should have position relative

Upvotes: 0

Trinh Hieu
Trinh Hieu

Reputation: 805

Here is my solution it works fine with html2canvas

You need to use style={{ position: "relative" }} in the parent element to keep the same size

Solution 1:

In className add h-auto to automatically default image height to avoid distortion if you use Tailwind

            <div className="row1 " style={{ position: "relative" }}>
                <Image
                  className="imgs1 h-auto"
                  width="0"
                  height="0"
                  sizes="100vw"
                  src={imgstores ? imgstores : "/no-image.png"}
                  alt="Logo"
                  style={{ objectFit: "cover" }}
                />
            </div>

Solution 2:

Set width={} and height={} and style height: "auto":

Even though I set the image height with height={120} it didn't understand so I had to add a style with height: auto

        <div className="row1 relative " style={{ position: "relative" }}>
                <Image
                  className="imgs1 "
                  width={120}
                  height={100}
                  src={imgstores ? imgstores : "/no-image.png"}
                  alt="Logo"
                  style={{ objectFit: "contain", height: "auto" }}
                />
              </div>

Upvotes: 0

Lonare
Lonare

Reputation: 4703

If you are using nextjs 13 then just use below:

<div className="relative rounded-md h-full p-3 border-2">
    <Image
        src={"../../../src.png"}
        width="0"
        height="0"
        sizes="100vw"
        className="w-full h-auto"
    />
</div>

Upvotes: 6

Dinesh Kumar
Dinesh Kumar

Reputation: 189

You need to use position: relative for parent element.

Upvotes: 15

Andrew Gillis
Andrew Gillis

Reputation: 3895

The wrapping div should have position: relative:

export default function Home() {
  return (
    <div>
      <div style={{width: '100px', height: '100px', position: 'relative'}}>
        <Image src={"/i.png"} layout='fill'/>
      </div>
    </div>
  )
}

This is a consequence of how position: absolute works. It's containing block will be the nearest ancestor element that has any position value but static (the initial value).

Upvotes: 92

Related Questions