Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Next/Image component downloads larger image than required #2677

Open
eliorg opened this issue Oct 17, 2024 · 1 comment
Open

Next/Image component downloads larger image than required #2677

eliorg opened this issue Oct 17, 2024 · 1 comment
Labels
type: bug code to address defects in shipped code

Comments

@eliorg
Copy link

eliorg commented Oct 17, 2024

I noticed next/image's size is set differently depending on where you host your Next.js project.

I uploaded a 1 page Next.js project displaying an image on Netlify and Vercel.

On Vercel, the image's intrinsic size is 1920x1674 - https://newapp-eight-tawny.vercel.app/
On Netlify the image, is intrinsic size is 3840x3348 - https://inquisitive-sunshine-89a4b0.netlify.app/

These values can be seen in the bottom right corner of each image below.

sreenshot

"The Rendered size is the portion of the page that the image takes up. The Intrinsic size is the original size of the image."

Here is the code for both pages

import Image from "next/image";
import animal from "../public/images/animal.jpg";

export default function Home() {
  return (
    <div>
        <Image className="w-full h-auto" src={animal} alt=""></Image>
    </div>
  );
}
@serhalp serhalp added the Next.js label Oct 17, 2024 — with Linear
@serhalp serhalp self-assigned this Oct 17, 2024
@serhalp serhalp removed the Next.js label Oct 18, 2024
@serhalp serhalp removed their assignment Oct 18, 2024
@serhalp
Copy link
Contributor

serhalp commented Oct 28, 2024

Hi @eliorg, thanks for writing in!

As far as we can tell, what's going on here is that next/image is rendering an <img> tag that looks like this:

<img
  alt=""
  loading="lazy"
  width="1920"
  height="1674"
  decoding="async"
  data-nimg="1"
  class="w-full h-auto"
  style="color:transparent"
  srcset="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fanimal.d9281202.jpg&amp;w=1920&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fanimal.d9281202.jpg&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fanimal.d9281202.jpg&amp;w=3840&amp;q=75"
>

The interesting bit is that srcset attribute on the last line. See here for more on srcset.

It seems that it's telling browsers that there's a 1x format available at https:[...snip...].jpg?w=1920 and a 2x format available at https:[...snip...].jpg?w=3840, and so if your browser decides to load the 2x format it ends up upscaled to 2x the original dimensions. There's a bit of Next.js specific documentation on this here, so it seems this is expected behaviour.

Netlify's image CDN allows upscaling, so it gladly returns a 3840 px wide upscaled image when requested (2x) and a 1920 px image when requested (1x). On the other hand, the built-in image optimization via Vercel ignores upscaling requests by rewriting requested widths greater than the original width on the fly. It looks like they even applied the same thing to the other built-in image CDN loaders. On Netlify this seems to go through another code path that doesn't have this workaround, so this doesn't happen.

The end result is that you see a "blurry" image on Netlify and a "normal" image on Vercel, unfortunately. Thanks for reporting this. We'll think about this a bit more on our end and see if we can come up with a fix. In the meantime, I believe you should be able to pass a single size to the sizes prop to work around this.

@serhalp serhalp added the type: bug code to address defects in shipped code label Oct 28, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: bug code to address defects in shipped code
Projects
None yet
Development

No branches or pull requests

2 participants