image icon indicating copy to clipboard operation
image copied to clipboard

Responsive image sizing

Open ArtCraft opened this issue 3 years ago • 10 comments

We live in a time when websites should work on a huge range of devices with different sizes and densities, it is not enough to have only one version of image... at least 2 versions of each file (1x and 2x) is a must for modern web, but in many cases it may be reasonable to have 3-4 sizes of each file in webp format + fallback to jpg/png, so each picture usually may be resized/converted to 2-4-6 or more versions.

Problems:

  • There is no way do define image sizes for high density image versions
  • Presets do not allow to use sizes property available for nuxt-img
  • (for @nuxt/content) Images inside .md files that included using .md syntax are not processed by @nuxt/image, it would be very nice if it is possible to set a default sizing using preset for those images

ArtCraft avatar Apr 17 '21 14:04 ArtCraft

for example

<nuxt-img src="/picture1.jpg" sizes="sm:200px, md:500px"  alt="test"></nuxt-img>

this generates following code

<img
   srcset="/_ipx/pic1.jpg?w=200 200w, /_ipx/pic1.jpg?w=500 500w"
   sizes="(max-width: 640px) 200px, 500px"  
   src="/_ipx/pic1.jpg?w=500"    
   alt="test"
/>

on retina display (device pixel ratio 2.0) optimal image sizes would be 400px and 1000px, but srcset attribute do not provide those sizes

what should be generated to look good is:

<img
   srcset="/_ipx/pic1.jpg?w=200 200w, /_ipx/pic1.jpg?w=400 400w, /_ipx/pic1.jpg?w=500 500w, /_ipx/pic1.jpg?w=1000 1000w"
   sizes="(max-width: 640px) 200px, 500px"
   src="/_ipx/pic1.jpg?w=1000" 
   alt="test"
/>

so there should be some way to define those sizes as well something like

<nuxt-img 
    srcset="200w, 400w, 500w, 1000w" 
    sizes="sm:200px, md:500px" 
    src="/picture1.jpg" 
    alt="test"
></nuxt-img>

almost like img tag but with skipped filenames in srcset which going to be filled in automatically

ArtCraft avatar Apr 17 '21 23:04 ArtCraft

Hi @ArtCraft. Thanks for detailed proposal. Supporting densities, for sure makes sense. But I am thinking if main purpose is that, we can think about easier interface like this:

<nuxt-img sizes="sm:200px, md:500px" densities="1x 2x">

This way we can easily auto calculate all required additional densities and omit close variants. Also as you mentioned about preset, we can allow a global (nuxt.config) option to specify required densities and remove need of specify it on each use case.

What do you think about this?

pi0 avatar May 13 '21 18:05 pi0

adding densities attribute should solve the problem

this is shorter compared to my proposal but involves some small "magic" transformation, i'm ok with it but i bet there are lot's of people who prefer «keep it simple and straightforward» approach

please beware that instruction like this <nuxt-img sizes="sm:200px, md:400px" densities="1x 2x"> contains a duplicate size: 200, 400, 400, 800

also 1x is redundant as long as you already provided a list of 1x sizes

I think both approaches can live side by side:

  • you can provide exact list of all sizes you want
  • or you can provide only 1x sizes and additional densities

ArtCraft avatar May 13 '21 23:05 ArtCraft

contains a duplicate size: 200, 400, 400, 800

This is why I mentioned about omit close variants. There is also possibly (without densities as well) that two variants lead to close widths like 200/220 which we should handle anyway. (~> #268)

also 1x is redundant

I agree but then we need to make it more clear that others are additional densities we generating if 1x is ommited (code readability) . Also, there might be valid cases for not needing 1x. (Imagine a website allows personalization to set the zoom level to 1.5. densities can be provided as a computed prop to only pass this)

you can provide exact list of all sizes you want

If there is a valid case for this, yes. But I would prefer to keep nuxt-image as minimal as possible. Avoiding more boilerplate that can lead to developer mistakes (simple example: one might simply forget to update manual calculations as global screens option or sizes prop changes) and is easier to learn with one option related to one functionality.

pi0 avatar May 14 '21 08:05 pi0

I think the density prop makes sense and is clearer for this. Although 1x is redundant I think it makes sense to have the user provide it so it's very intuitive in the code with what is happening. @pi0 has a valid point as well with sometimes wanting densities that do not include 1x.

My PR #227 used the descriptors to calculate the widths and then would remove any duplicates before generating the images. I could update this to also take into account close width variants, what threshold would you be looking for? I'm happy to keep working on the PR and update it to use density instead of srcset as a prop and only accept pixel descriptors, or would you require a different PR?

dannyalder88 avatar May 14 '21 08:05 dannyalder88

@dannyalder88 Implementing only density in #227 and other PR for #268 would be nice 🙏

pi0 avatar May 14 '21 09:05 pi0

@pi0 why not calculate density automatically at least by default, based on device pixel ratio with window.devicePixelRatio? I hardly doubt anyone would want to load something other than what is appropriate for a device-specific scale?

AndrewBogdanovTSS avatar Jun 03 '21 17:06 AndrewBogdanovTSS

@AndrewBogdanovTSS Would be nice to automate and vary by device but we don't have access to window.devicePixelRatio on the server-side. This will cause a hydration error. (on client-side it also needs a watcher for multi-screen setups with different density)

pi0 avatar Jun 04 '21 14:06 pi0

Maybe there could be a way to set density on the server based on user agent?

AndrewBogdanovTSS avatar Jun 04 '21 15:06 AndrewBogdanovTSS

Density is taken care of by the browser, it makes no sense to add this here. What would make sense is making it possible to define sizes in presets.

hyvyys avatar Dec 04 '21 14:12 hyvyys