vercel / next.js

The React Framework
https://nextjs.org
MIT License
126.86k stars 26.97k forks source link

Warning: `Image with src "URL" has either width or height modified, but not the other.` #61908

Open ahkhanjani opened 9 months ago

ahkhanjani commented 9 months ago

Link to the code that reproduces this issue

https://codesandbox.io/p/devbox/charming-field-hlgq68?file=%2Fapp%2Fpage.tsx%3A9%2C2

To Reproduce

  1. Get an image, including its dimensions from a CMS (in my case Hygraph).
  2. Render it using next/image with both width and height set as numbers.

Current vs. Expected behavior

I'm setting both width and height. This warning shouldn't appear.

Provide environment information

Operating System:
  Platform: win32
  Arch: x64
  Version: Windows 11 Pro
Binaries:
  Node: 20.11.0
  npm: N/A
  Yarn: N/A
  pnpm: N/A
Relevant Packages:
  next: 14.1.0
  eslint-config-next: 14.1.0
  react: 18.2.0
  react-dom: 18.2.0
  typescript: 5.3.3
Next.js Config:
  output: N/A

Which area(s) are affected? (Select all that apply)

Image optimization (next/image, next/legacy/image)

Which stage(s) are affected? (Select all that apply)

next dev (local)

Additional context

The problem is not new and it's been like this since early next 13 when I bootstrapped the project so I don't think it's version specific.

What I'm doing is basically get the image URL and its real dimensions from Hygraph, hardcode the width that I want, and calculate the corresponding height of the image and pass it to the <Image> component. Here's how it looks:

const { src, width, height } = imageData;
if (!src || !width || !height) {
  return null;
}
const aspectRatioHeight = (+height/ +width) * 200;

return <Image src={src} alt="" width={200} height={aspectRatioHeight} />;

width and height are string values. I'm converting them to numbers using the plus sign.

I've tried setting height to auto and even 0 using the style attribute and Tailwind but it didn't work.

coffeecupjapan commented 9 months ago

@ahkhanjani Hi. In Next.js image component source code, they compare img.height with img.getAttribute("height").

https://github.com/vercel/next.js/blob/898f74e7292061180fdfbcfb580a527a3def03b3/packages/next/src/client/image-component.tsx#L154

And Although your height calculation function always calculate after the decimal point for height (img.getAttribute("height")), img.height somehow only get rounded number of height, and comparison always fails and warn occurs.

Therefore for easy fix, you can just add Math.round or Math.ceil in your height calculation function and warn would be disappeared.

  const aspectRatioHeight = Math.round((+realHeight / +realWidth) * 200);
ahkhanjani commented 8 months ago

Thank you @coffeecupjapan.

And Although your height calculation function always calculate after the decimal point for height (img.getAttribute("height")), img.height somehow only get rounded number of height, and comparison always fails and warn occurs.

So the error is completely wrong. It should show an accurate error.

ahkhanjani commented 8 months ago

@coffeecupjapan I tried rounding the height and wow, some images work with Math.floor(), some with Math.ceil(). There is probably some weird internal rounding going on. Any ideas?