Your Images Are (Probably) Oversized

Photo by Milena Trifonova on Unsplash
Are you setting the sizes
attribute on your <img/>
tags?
No?
Then you're most certainly serving images that are larger than they should be. Even for large-width (e.g. desktop) screens.
Oh, you're using NextJS's <Image/>
component and you're telling me you don't need to worry about it? Oh my sweet summer child.
A Reality Check
You're implementing a beautiful landing page your designer just created, and like most landing pages, it has a hero section with a prominently featured image, something like this:
In the example above, the hero image stretches both horizontally and vertically (but of course, always maintaining its original aspect ratio) covering almost the entire screen, and thus, its rendered size will depend directly on the dimensions of the user's device.
Thankfully, your designer also understands that, and to ensure that this image looks good on any screen size, they send you a very high resolution image, let's say 3600x2400 pixels. With that many pixels, it will look sharp even on the largest monitors.
The problem, however, is that the majority of your users won't have screens that are big enough to make use of all those pixels, so having them download an image this big is essentially a waste of both bandwidth and compute, which could be better utilized for other things.
Ah! But I use NextJS
<Image>
component, so I won't have this issue, as it will optimize my images so that they are never bigger than they should be.
So, without a second thought you summon the fabled NextJS <Image/>
component and use it like this:
<Image priority // We want to load this eagerly, as this is part of the FCP src="/hero-image.jpg" alt="Moutains" className="relative w-screen h-screen object-cover" width={3600} height={2400}/>
If this looks right to you, I have some bad news.
Let me show you something:
This is that same landing page we saw above, but now seen through a much narrower viewport, sized at 425px to be precise.
Now, if using NextJS <Image>
component this way was enough to have images sized appropriately, in the example above we'd expect to be serving an image that is much smaller than the original one.
However, look at what we actually get: