image icon indicating copy to clipboard operation
image copied to clipboard

Image size set to `1w` if sizes is set to `100vw`

Open stijns96 opened this issue 1 year ago • 12 comments

Somehow 100vw will be converted to a 1w and 2w url and I don't understand why.

Local

<img
  sizes="(max-width: 640px) 100vw, (max-width: 768px) 50vw, 400px"
  srcset="
    /_ipx/w_1/twitter-image.png     1w,
    /_ipx/w_2/twitter-image.png     2w,
    /_ipx/w_320/twitter-image.png 320w,
    /_ipx/w_400/twitter-image.png 400w,
    /_ipx/w_640/twitter-image.png 640w,
    /_ipx/w_800/twitter-image.png 800w
  "
  src="/_ipx/w_800/twitter-image.png"
/>

Storyblok

<img
  sizes="(max-width: 640px) 100vw, (max-width: 768px) 50vw, 400px"
  srcset="
    https://a.storyblok.com/f/23194/3000x2000/09das0980/image.png/m/1x0     1w,
    https://a.storyblok.com/f/23194/3000x2000/09das0980/image.png/m/2x0     2w,
    https://a.storyblok.com/f/23194/3000x2000/09das0980/image.png/m/320x0 320w,
    https://a.storyblok.com/f/23194/3000x2000/09das0980/image.png/m/400x0 400w,
    https://a.storyblok.com/f/23194/3000x2000/09das0980/image.png/m/640x0 640w,
    https://a.storyblok.com/f/23194/3000x2000/09das0980/image.png/m/800x0 800w
  "
  src="https://a.storyblok.com/f/23194/3000x2000/09das0980/image.png/m/800x0"
/>

stijns96 avatar Aug 21 '24 20:08 stijns96

Meanwhile I get why. There is no breakpoint to match, but still this should work. I like the way the srcset is build up from the sizes, but sometimes it's works against it.

Sometimes it would he better to just have an array of widths that the srcset should be build of.

Most of the time you only need a px size if the container reaches it's max width. Everything below should use vw

stijns96 avatar Aug 22 '24 08:08 stijns96

It's actually really weird and it's very strange that this issue doesn't have more upvotes as it basically affects all providers.

The problem lies in that logic: https://github.com/nuxt/image/blob/3175790db095c9a46535cdb0ae9cbb18e0b48bc2/src/runtime/utils/index.ts#L128-L136

For a size input such as "sm: 100vw lg:480px" this function should return a sizes object such as:

sizes = {
  lg: '480px',
  sm: '100vw',
}

But whenever a size is provided without a media query, this function sets it to 1px in size. So: "100vw lg:480px" will return:

sizes = {
  '1px': '100vw',
  lg: '480px',
}

Then further there is some logic that converts the keys to their actual screens values, so the object will be transformed with actual pixel values instead of screen keys, let's says like this:

sizes = {
 '1px': '100vw',
 1280: '480px',
}

And finally with default densities being [1, 2] the sizes object will multiply its keys by x2 hence the 1w and 2w that are so weird. Then it seems also that the package doesn't generate all the srcsets matching the screens defined in nuxt config.

Anyway long story short:

  • a size without a media query is interpreted incorrectly
  • srcset doesn't include all breakpoints.

This is a major inconvenience and make this package pretty much useless without a fix.

dbismut avatar Sep 04 '24 07:09 dbismut

Hi @dbismut ,

Nice explenation! I already moved away from this package... it indeed makes it useless now.

stijns96 avatar Sep 04 '24 09:09 stijns96

Do you have a drop in replacement?

dbismut avatar Sep 04 '24 09:09 dbismut

Do you have a drop in replacement?

Well, I created my own image component. It's fully based on the Storyblok image service

stijns96 avatar Sep 04 '24 09:09 stijns96

Do we really need to specify 100vw on the start? Isn’t enough this? xs:100vw sm:100vw md:100vw lg:100vw xl:100vw 2xl:100vw

(Related: #267 )

iBobik avatar Oct 05 '24 15:10 iBobik

Of course this can work but it is fastidious, it's like setting media queries for every breakpoint for each responsive class, that doesn't make sense.

Plus it is supposed to work from the docs.

Also nuxt/image is confusing breakpoints and screen variants which are two different things.

dbismut avatar Oct 06 '24 19:10 dbismut

Do you have a drop in replacement?

Well, I created my own image component. It's fully based on the Storyblok image service

@stijns96 Do you happen to have this component available someplace?

codeflorist avatar Jan 22 '25 16:01 codeflorist

Hi everyone, I can confirm I'm experiencing a similar issue with @nuxt/image v1.10.0 and Nuxt v3.x.x

When using a simple sizes="100vw" (along with width and height attributes for the original image, and densities="1x 2x"), the generated srcset incorrectly uses scaling parameters like s_1x1 and s_2x2 (or w_1, w_2), resulting in a tiny intrinsic image size.

<!-- Example of problematic NuxtImg tag -->
<NuxtImg
  src="/images/hero-background.webp"
  width="3070"
  height="1726"
  sizes="100vw"
  densities="1x 2x"
  alt="Description"
/>
<!-- Leads to srcset like: /_ipx/s_1x1/image.webp 1w, /_ipx/s_2x2/image.webp 2w -->

However, I found that the following workaround using more explicit media conditions in the sizes attribute resolves the issue for me:

<NuxtImg
  src="/images/hero-background.webp"
  width="3070"
  height="1726"
  sizes="(max-width: 640px) 100vw, (max-width: 768px) 100vw, (max-width: 1024px) 100vw, (max-width: 1280px) 100vw, (max-width: 1536px) 100vw, 100vw"
  densities="1x 2x"
  alt="Description"
/>

This generates a correct srcset with appropriately scaled images (e.g., /_ipx/q_80&s_320x180/images/hero-background.webp 320w, ...). Hopefully, this information helps in diagnosing and fixing the underlying parsing logic for the sizes attribute when a default/fallback value without a breakpoint prefix is used.

pmochine avatar May 21 '25 20:05 pmochine

Same issue, NuxtImg is generating very confusing and incorrect srcset... Can't understand the link between image.screens in nuxt.config.ts and the generated srcset.

nuxt.config.ts

  image: {
    screens: {
      'sm': 640,
      'lg': 1024,
      'xxl': 1536,
    }
  }

.vue file

<NuxtImg sizes="166vw sm:133vw lg:100vw xxl:100vw" src="..." />

Output HTML

<img data-nuxt-img=""
   sizes="(max-width: 640px) 166vw, (max-width: 1024px) 133vw, (max-width: 1536px) 100vw, 100vw" 
   srcset="http://localhost:3000/cover.jpg?width=2&q=85 2w,
    http://localhost:3000/cover.jpg?width=4&q=85 4w,
    http://localhost:3000/cover.jpg?width=851&q=85 851w,
    http://localhost:3000/cover.jpg?width=1024&q=85 1024w,
    http://localhost:3000/cover.jpg?width=1536&q=85 1536w,
    http://localhost:3000/cover.jpg?width=1702&q=85 1702w,
    http://localhost:3000/cover.jpg?width=2048&q=85 2048w,
    http://localhost:3000/cover.jpg?width=3072&q=85 3072w"
  src="http://localhost:3000/cover.jpg?width=3072&q=85" />

It should be provide only sm lg & xxl sizes, and the 2w & 4w breakpoints are completly absurd ^^

maximelebreton avatar Aug 13 '25 11:08 maximelebreton

Hi everyone, I can confirm I'm experiencing a similar issue with @nuxt/image v1.10.0 and Nuxt v3.x.x

When using a simple sizes="100vw" (along with width and height attributes for the original image, and densities="1x 2x"), the generated srcset incorrectly uses scaling parameters like s_1x1 and s_2x2 (or w_1, w_2), resulting in a tiny intrinsic image size.

<!-- Example of problematic NuxtImg tag -->
<NuxtImg
  src="/images/hero-background.webp"
  width="3070"
  height="1726"
  sizes="100vw"
  densities="1x 2x"
  alt="Description"
/>
<!-- Leads to srcset like: /_ipx/s_1x1/image.webp 1w, /_ipx/s_2x2/image.webp 2w -->

However, I found that the following workaround using more explicit media conditions in the sizes attribute resolves the issue for me:

<NuxtImg
  src="/images/hero-background.webp"
  width="3070"
  height="1726"
  sizes="(max-width: 640px) 100vw, (max-width: 768px) 100vw, (max-width: 1024px) 100vw, (max-width: 1280px) 100vw, (max-width: 1536px) 100vw, 100vw"
  densities="1x 2x"
  alt="Description"
/>

This generates a correct srcset with appropriately scaled images (e.g., /_ipx/q_80&s_320x180/images/hero-background.webp 320w, ...). Hopefully, this information helps in diagnosing and fixing the underlying parsing logic for the sizes attribute when a default/fallback value without a breakpoint prefix is used.

This approach seems to be the literal opposite of what's in this module's documentation: "This default size is used up until the next specified screen width, and so on. Each specified size pair applies up - so md:400px means that the image will be sized 400px on md screens and up." .

m-shum avatar Aug 20 '25 21:08 m-shum

I still face the problem in v1.11.0 .

<NuxtImg
  src="/STATIC_IMG.jpg"
  class="absolute inset-0 object-cover object-center size-full"
  width="2048"
  height="1365"
  sizes="100vw"
  format="webp"
 />

and I only the small version of the image gets rendered like 2x2px

<img width="2048" height="1365" data-nuxt-img="" sizes="100vw" srcset="/_ipx/f_webp&amp;s_1x1/chalupa/chalupa-6.jpg 1w, /_ipx/f_webp&amp;s_2x2/chalupa/chalupa-6.jpg 2w" class="absolute inset-0 object-cover object-center size-full" src="/_ipx/f_webp&amp;s_2x2/chalupa/chalupa-6.jpg">

Even when I omit the with and height attributes the result is the same.

Without the sizes attribute the image loads correctly

MartinLednar avatar Sep 04 '25 18:09 MartinLednar