Open timbenniks opened 3 years ago
Thanks for the detailed issue @timbenniks
How would you see such feature usage using <nuxt-picture>
component without being overkill?
It is possible though to use the standard <picture>
element and use Nuxt Image programmatically: https://image.nuxtjs.org/api/$img
With the current nuxt-picture
, one cannot use different versions of image/src with media selectors but is simply an img
replacement with the ability for serving modern formats alongside legacy support.
As @Atinux mentioned, It is possible to directly use $img
and $img.getSizes
API creating any structure like media
variable sources. We can also create a shortcut like <nuxt-source>
to make it sexier:
<picture>
<nuxt-source
media="(orientation: landscape)"
src="image.jpg"
sizes="xs:200px md:500px lg:1024"
/>
<nuxt-source
media="(orientation: portrait)"
src="image-portrait.jpg"
sizes="xs:200px md:500px lg:1024"
/>
<nuxt-img
src="image.jpg"
width="200"
/>
</picture>
POC: https://codesandbox.io/s/intelligent-water-nbikw?file=/pages/index.vue
In addition, we probably support scoped slots for nuxt-picuture
, this way we can make it more minimalistic. (subject to discuss when added)
One alternative would be supporting more complex syntax for sizes
prop. Combining source and sizes. We had it in previous versions but removed it due to complexities for simpler usecases and implementation.
Different approaches possible.
<nuxt-picture>
<nuxt-img sizes="sm:100vw md:50vw lg:400px" src="option-1.png" media="(orientation: landscape)">
<nuxt-img sizes="sm:100vw md:50vw lg:400px" src="option-2.png" media="(orientation: portrait)">
</nuxt-picture>
<nuxt-picture>
<nuxt-source sizes="sm:100vw md:50vw lg:400px" src="option-1.png" media="(orientation: landscape)">
<nuxt-source sizes="sm:100vw md:50vw lg:400px" src="option-2.png" media="(orientation: portrait)">
</nuxt-picture>
<nuxt-picture :sources="[{
src: 'image-1.png',
media: '(orientation: landscape)'
sizes: 'sm:100vw md:50vw lg:400px'
}, {
src: 'image-2.png',
media: '(orientation: portriat)'
sizes: 'sm:100vw md:50vw lg:400px'
}]"/>
img
tags inside picture
unless checking parent for conditional rendering (which is anti-pattern)I guess best would be going with 2 (nuxt-source and slot) 🙈
I think this: https://codesandbox.io/s/intelligent-water-nbikw?file=/pages/index.vue is the way to go.
I would very much like to have this feature.
My team is migrating to webp format for all images, yet we still have almost 5% of our userbase on browsers that are on older browsers that don't support webp, so a real, automatic fallback to .png would be extremely helpful.
@johncastorina webp with fallback is already supported using nuxt-picture
There is a legacyFormat prop to set the fallback https://image.nuxtjs.org/components/nuxt-picture#legacyformat
I guess best would be going with 2 (nuxt-source and slot) :see_no_evil:
@pi0 I agree. The other two approaches both have obvious issues.
While working on my bolierplate repository (which is not ready for open source yet), i ended up writing a quite complex image component trying to abstract away missing features like this one.
Some other issues that that are related to this and make proper responsive image handling hard:
Yes, I am confused about the current setup – what would be the use case if it doesn't support multiple sources? - isn't the only purpose for the picture tag to have different images altogether, such as a landscape image and a portrait image for different orientations?
Is there anything further planned for this request? Just stumbled into this issue myself having assumed that nuxt-picture
would allow me to use all the features of native picture
😅
I guess this library is no longer maintained as much as it was - does anyone know any alternative solutions which do support the picture tag?
Actually we are back at it and we were waiting some pending features on the Nitro side, very sorry about this 😬
Ah okay, fantastic. It's open source so I completely understand these things take time. Just wanted to know whether I should be looking elsewhere or not but I will hold out for the update :). Thanks!
Hey is there a PR that is being reviewed for this update? My team is open to working on a PR since we are waiting for this feature for our project. Thanks!!
@toddpadwick > I guess this library is no longer maintained as much as it was - does anyone know any alternative solutions which do support the picture tag?
Have you found a replacement for the picture tag for vue until guys add this support for nuxt-picture?
@the-lensky Just write your own <picture>
. That's what we do, just by leveraging the $img
helper function to get the URLs. We prefer it, it gives us full control over the output.
@the-lensky I am also doing what @AndrewTannerNA does when we need the picture tag, but for the most part, I'm just trying to make do with the nuxt-image as much as possible. Because when we've used the $img helper function to create our own picture tag, its much slower on page speed. But luckily, most of our projects don't require the picture tag too often.
Does anyone have a clean example of a manual implementation they may be able to share? I'm trying to display different sources based on display size and having a hard time getting this to work correctly.
I followed @timbenniks great example over at https://codesandbox.io/s/intelligent-water-nbikw?file=/pages/index.vue without problems.
<!-- components/Something.vue --->
<picture
v-for="(image, index) in images"
:key="index"
>
<nuxt-source media="(orientation: landscape)" :src="image.src" />
<nuxt-source
media="(orientation: portrait)"
:src="image.portraitSrc"
/>
<nuxt-img
srcset=""
:src="image.src"
:alt="image.alt"
width="1920"
height="1080"
format="webp"
/>
</picture>
<!-- components/NuxtSource.vue -->
<template>
<source :media="media" :srcset="cSizes.srcset" :sizes="cSizes.sizes" />
</template>
<script>
export default {
props: {
src: { type: String },
media: { type: String },
sizes: { type: String },
},
computed: {
cSizes() {
const img = useImage()
return img.getSizes(this.src, {
sizes:
this.sizes ||
'xs:320px sm:640px md:768px lg:1024px xl:1280px xxl: 1536px 2xl:1536px',
})
},
},
}
</script>
Is this still planned? Without this, the NuxtPicture component is missing the most essential feature of the native picture element. Given the component's name, people expect NuxtPicure to work just like its native counterpart, with the added benefit of image optimization.
It seems the picture tag implementation in the nuxt/image package is lacking basic picture tag features.
The picture tag and its sources (who act like regular images - with srcset and sizes, but with the addition of the "media" attribute) is meant to be able to show a different image for different matches in that media attribute.
Currently one source is added in the code which acts as a normal image tag with srcset and sizes. However, there is no mention of the media attribute in the implementation. see: https://github.com/nuxt/image/blob/main/src/runtime/components/nuxt-picture.vue
A picture tag is mainly used in a more "Art Direction" way and not “Resolution Switching”.
<picture>
is capable of handling resolution switching, however you shouldn’t use it if that’s all you need. In such cases stick with a regularsrcset
andsizes
.Example of average picture tag usage:
These two images are different. Not just their width/height, they are actually different files with different aspects ratios and compositions. Each one is a
source
in the picture tag. Each of these<source />
tags also has asrcset
and asizes
attribute so they behave like a normal image nuxt image would. They have an additionalmedia
attribute which defines when they are shown. This field has a media query in it that tells the browser in which context to show the source.An HTML example:
You can of course also use the
picture
tag for file type support etcWith the above in mind we should be able to add multiple images into the nuxt picture tag so sources can be generated with
media
attributes.See image for differences:![img-picture](https://user-images.githubusercontent.com/121096/120493476-46db2600-c3bb-11eb-99f7-48609772be7a.png)