31

I am using NextJS Image component. I want the image to fill 100% width and take as much height as it needs to maintain the aspect ratio. I have tried many different variations of this code but it will not work unless I define a fixed height on the parent div.

export default function PhotoCard({ img }: Props) {
      return (
        <div className="relative w-full h-32 my-2">
          <Image alt={img.title} src={img.url} layout="fill" objectFit="cover" />
        </div>
      );
    }

This is the current behaviour images in app

juliomalves
  • 42,130
  • 20
  • 150
  • 146
Jkaram
  • 611
  • 2
  • 7
  • 13

4 Answers4

66

From Next.js 13, the next/image component allows styling the underlying image directly using style/className. This means you can apply width: 100% and height: auto on the Image component directly.

import Image from 'next/image';

<Image
    src={img1}
    width="0"
    height="0"
    sizes="100vw"
    style={{ width: '100%', height: 'auto' }}
/>

Or, if using Tailwind CSS.

import Image from 'next/image';

<Image
    src={img1}
    width="0"
    height="0"
    sizes="100vw"
    className="w-full h-auto"
/>

Before Next.js 13, the above feature is only available through next/future/image, and from version 12.2, next/future/image was still experimental and can be enabled in next.config.js under the experimental flag.

module.exports = {
    experimental: {
        images: {
            allowFutureImage: true
        }
    },
    // Other configs
}
juliomalves
  • 42,130
  • 20
  • 150
  • 146
4

As Next.js has mentioned in their documentation, width and height properties are required in order to avoid layout shift, using layout="fill" will only fill the container height and width that is previously set. This basically means that in order to maintain the aspect ratio, you have to know the image height and width in advance.

Luckily though, Next.js also provided us a work around with this problem with an event called onLoadingComplete, which gives us an event parameter that contains both image natural height and width.

<Image
   layout="fill"
   src="/cat.jpg"
   onLoadingComplete={e => console.log(e)} // {naturalHeight: ..., naturalWidth: ...}
/>

There are plenty of options that you can do to maintain image aspect ratio with this information, like useState to set the height and the width of the element or make the image responsive, depends on your need. In any case, hope this was helpful.

raven2218
  • 61
  • 3
  • 1
    This should be higher up! Setting only one dimension for images and auto-ing the other is a pretty common design in normal images, I wonder why NextJS can't support that feature more easily. – sayandcode Oct 05 '22 at 16:21
  • `layout` is deprecated https://nextjs.org/docs/api-reference/next/legacy/image – Mo. Dec 12 '22 at 02:16
  • 2
    @Mo. The future image component looks promising tbh. – raven2218 Dec 13 '22 at 03:55
0

I have found a solution without using next/future/image and with using css with width-[100%] on the parent div like so.

           <div
              className="mx-auto w-[100%] md:bg-card md:w-[720px] max-w-4/5"
              key={img.imageProps.src}
            >
              <Image
                placeholder="blur"
                {...img.imageProps}
                layout={'responsive'}
                alt={`${chapterData.chapterNumber} image`}
              />
            </div>

{...img.imageProps} is a object that looks like this that has original height and width.

export type ImageProps = {
  blurDataURL: string;
  src: string;
  height: number;
  width: number;
  type?: string | undefined;
};

You can get these image props using something like plaiceholder, it comes loaded with blurImage data url.

const convertImages = async (image: string) => {
    const { base64, img } = await getPlaiceholder(image, { size: 14 });
    return {
      imageProps: {
        ...img,
        blurDataURL: base64,
      },
    };
  };

OR

You can create your own function to get the height and width for each image individually before displaying it, which is required by the next <Image/> Hope this helps.

wick3d
  • 1,164
  • 14
  • 41
-1

You can try to set width and height with "%" way..

<Image src={image.url} alt={image.title} width="100%" height="100%" layout="responsive" objectFit="contain"/>

or you can set the width with the "vw" property like this..

<Image src={image.url} alt={image.title} width="100vw" height="100%" layout="responsive" objectFit="contain"/>
Manfre
  • 656
  • 5
  • 12
  • 30