Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use Image component in Next.js with unknown width and height

Since version 10, Next.js comes with the built-in Image component which provides the feature of image optimization and resizing image responsively. I like it a lot and I've been using it across my website for images with a fixed size. According to the official documentation, width and height are required props unless it's for layout=fill.

Now, I would like to use Image component even when I don't know width and height ahead of time. I have blog resources that come from a CMS where the exact size of the image is unknown. In this case, is there any way I could use Image component?

Any help would be appreciated.

like image 211
bubbleChaser Avatar asked Feb 24 '21 15:02

bubbleChaser


People also ask

What happens if you do not put a width and height of an image in HTML what size does it end up?

If you do not supply height and width explicitly the <img> element will be rendered at 0x0 until the browser can size it based on the file. When this happens it causes a visual reflow of the page once the image loads, and is compounded if you have multiple images on the page.

Can I use IMG tag in next JS?

There are two ways you can display images in Next. js, you either use the conventional <img> tag or a specialized <Image/> component that is unique to Next. The differences between these tags are quite much, but they pretty much do the same thing; which is to display images to the browser.

What are image widths used for in next/image component?

These widths are used when the next/image component uses layout="responsive" or layout="fill" to ensure the correct image is served for user's device. If no configuration is provided, the default below is used. You can specify a list of image widths using the images.imageSizes property in your next.config.js file.

How to specify device width breakpoints in next/image component?

If you know the expected device widths of your users, you can specify a list of device width breakpoints using the deviceSizes property in next.config.js. These widths are used when the next/image component uses layout="responsive" or layout="fill" to ensure the correct image is served for user's device.

What are the props required for the <image> component?

The component <Image /> requires some props like src, width, height. The <image /> component optionally accepts the following properties. <Image width= {500} height= {500} src= {imgSrc} alt="images name" />

How do I use images in JSX code?

Images load as they are scrolled into the viewport. The first step to use it is to import it from the Next.js library: And then it’s a matter of using it in your JSX code, passing it at least an src property: If you want to use images stored inside your Next.js project, an easy way is to put them inside the /public folder.


Video Answer


5 Answers

Yeah, you could use it with the layout=fill option you mentioned.

On this case, you're gonna need to set an "aspect ratio" for your images

<div style={{ position: "relative", width: "100%", paddingBottom: "20%" }} >
  <Image
    alt="Image Alt"
    src="/image.jpg"
    layout="fill"
    objectFit="contain" // Scale your image down to fit into the container
  />
</div>

You can use objectFit="cover" too and it'll scale your image up to fill all the container.

The downside of this approach is that is gonna be attached to the width you specify, it could be relative such as "100%" or absolute e.g. "10rem", but there's no way to set like an auto width and height based on the size of your image, or at least no yet.

like image 86
edgarlr Avatar answered Oct 22 '22 23:10

edgarlr


πŸ‘‹

I had the same issue too: I wanted to use Image from next/image in a masonry ImageList from MUI...

Anyway, this is the trick I used to get the size of my image and so to handle the size of the container:

    import React, { FC, useState } from 'react';
    import styled from 'styled-components';
    import Image from 'next/image';
    
    interface Props {
      src: string;
    }
    export const MasonryItem: FC<Props> = ({ src }) => {
      const [paddingTop, setPaddingTop] = useState('0');
    
      return (
        <Container style={{ paddingTop }}>
          <Image
            src={src}
            layout="fill"
            objectFit="contain"
            onLoad={({ target }) => {
              const { naturalWidth, naturalHeight } = target as HTMLImageElement;
              setPaddingTop(`calc(100% / (${naturalWidth} / ${naturalHeight})`);
            }}
          />
        </Container>
      );
    };
    
    const Container = styled.div`
      position: relative;
    `;

The idea: get size of image when it's loaded, calc the ratio and use it to make the container fill the require space with padding-top. This way no matter your image size the container will be fit to it.

Remark, I didn't use width or height on the container because I didn't need it with my project, but maybe you will have to set one of both for your project.

As I'm still beginning with React & NextJS & typescript, maybe the solution can be prettier, if someone have an idea to improve it I'll be pleased to read it! πŸ™

like image 11
Paul Bompard Avatar answered Oct 22 '22 23:10

Paul Bompard


If you want to preserve the ratio of the original image you can do it like this:

<div
  style={{
    width: 150,
    height: 75,
    position: "relative",
  }}>
<Image
  src={"/images/logos/" + merger.companyLogoUrl}
  alt={merger.company}
  layout="fill"
  objectFit="contain"
/>

The image will fill to be as big as the container allows. So if you know your images are wider than they are long, for example, you could just set the width on the container and then set the container height to be bigger than the predicted image height.

So, for example, if you're working with wide images you can set the container width to be 150px, then as long as the container height is larger than the image height the image will show up at the height of the original ratio.

like image 4
Santiago Angel Avatar answered Oct 23 '22 01:10

Santiago Angel


I wrote a blog post, detailing how to get the size of remote images, while also using SSG. How to use Image component in Next.js with unknown width and height

import Image from "next/image";
import probe from "probe-image-size";

export const getStaticProps = async () => {
  const images = [
    { url: "https://i.imgur.com/uCxsmmg.png" },
    { url: "https://i.imgur.com/r4IgKkX.jpeg" },
    { url: "https://i.imgur.com/dAyge0Y.jpeg" }
  ];

  const imagesWithSizes = await Promise.all(
    images.map(async (image) => {
      const imageWithSize = image;
      imageWithSize.size = await probe(image.url);

      return imageWithSize;
    })
  );

  return {
    props: {
      images: imagesWithSizes
    }
  };
};
//...
export default function IndexPage({ images }) {
  return (
    <>
      {images?.map((image) => (
        <Image
          key={image.url}
          src={image.url}
          width={image.size.width}
          height={image.size.height}
        />
      ))}
    </>
  );
}
 
like image 1
Elfandrei Avatar answered Oct 22 '22 23:10

Elfandrei


nothing wasn't helped me from above variants, but i tried resolve issue another way, it works for me:

const [imageSize, setSmageSize] = useState({
  width: 1,
  height: 1
 });
    
<Image
  src={imgPath}
  layout="responsive"
  objectFit="contain"
  alt={alt}
  priority={true}
  onLoadingComplete={target => {
    setSmageSize({
      width: target.naturalWidth,
      height: target.naturalHeight
    });
   }}
  width={imageSize.width}
  height={imageSize.height}
/>
like image 1
Oleksii Avatar answered Oct 23 '22 00:10

Oleksii