[next/image] Responsive images with "art direction" #19880
-
I am using the The idea is that based on media queries (all I need is a certain width breakpoint in this case), change the src of the image. For example, on desktop have a more landscape image, and on mobile show an image that is more of a square. Here is the example from the MDN docs: <picture>
<source media="(max-width: 799px)" srcset="elva-480w-close-portrait.jpg">
<source media="(min-width: 800px)" srcset="elva-800w.jpg">
<img src="elva-800w.jpg" alt="Chris standing up holding his daughter Elva">
</picture> How can I achieve this using the Image component? My only idea so far is to have multiple Thanks. |
Beta Was this translation helpful? Give feedback.
Replies: 7 comments 32 replies
-
Your suggestion should work fine. If you hide your elements by using CSS |
Beta Was this translation helpful? Give feedback.
-
The problem with this approach is when you set |
Beta Was this translation helpful? Give feedback.
-
I've had this issue before. The problem with display: none is I believe the images are still downloaded, so it's an insane cost to have like 3 downloads for every image at all times. So I ended up making up all images load lazy so that this doesn't happen. It's not a great work around at all because lazy loading every image isn't optimized either, but it wasn't a production site. I think the only way to do it correctly is with javascript and not CSS media queries |
Beta Was this translation helpful? Give feedback.
-
We ended up writing our own We'll iterate some more internally, and publish it at a later time, when we've tested it fully. |
Beta Was this translation helpful? Give feedback.
-
Update: We have extracted the core logic from This allows usage outside of
Exampleimport { unstable_getImgProps as getImgProps } from 'next/image'
export default function Page() {
const common = { alt: 'Hero', width: 800, height: 400 }
const { props: { srcSet: dark } } = getImgProps({ ...common, src: '/dark.png' })
const { props: { srcSet: light, ...rest } } = getImgProps({ ...common, src: '/light.png' })
return (<picture>
<source media="(prefers-color-scheme: dark)" srcSet={dark} />
<source media="(prefers-color-scheme: light)" srcSet={light} />
<img {...rest} />
</picture>)
} PR: #51205 |
Beta Was this translation helpful? Give feedback.
-
Art Direction hero image with preloading: import {
unstable_getImgProps as getImgProps,
ImageProps,
StaticImageData,
} from 'next/image'
import Head from 'next/head'
const AdaptiveImage = ({
className,
alt = 'Hero image',
fill = true,
priority = true,
sizes = '100vw',
breakpoint = 640,
desktopImage,
mobileImage,
style = { objectFit: 'cover' },
...props
}: {
breakpoint?: number
desktopImage: StaticImageData
mobileImage: StaticImageData
} & Partial<ImageProps>) => {
const commonPreload = {
rel: 'preload',
as: 'image',
imageSizes: sizes,
}
const common = { alt, fill, priority, sizes, style, ...props }
const { srcSet: desktop } = getImgProps({ ...common, src: desktopImage }).props
const { srcSet: mobile, ...rest } = getImgProps({ ...common, src: mobileImage }).props
const desktopMedia = `(min-width: ${breakpoint}px)`
const mobileMedia = `(max-width: ${breakpoint - 1}px)`
return (
<>
<Head>
<link
{...commonPreload}
media={desktopMedia}
href={desktopImage.src}
imageSrcSet={desktop}
/>
<link
{...commonPreload}
media={mobileMedia}
href={mobileImage.src}
imageSrcSet={mobile}
/>
</Head>
<picture className={className}>
<source media={desktopMedia} srcSet={desktop} />
<source media={mobileMedia} srcSet={mobile} />
<img alt={alt} {...rest} />
</picture>
</>
)
}
export default AdaptiveImage Usage: import HeroDesktop from './hero-desktop.png'
import HeroMobile from './hero-mobile.png'
<AdaptiveImage
alt='My Hero'
desktopImage={HeroDesktop}
mobileImage={HeroMobile}
/> |
Beta Was this translation helpful? Give feedback.
-
It's a great solution, unfortunately it won't work with the App Router. Any idea on how to make it working? |
Beta Was this translation helpful? Give feedback.
Update: We have extracted the core logic from
next/image
into a newunstable_getImgProps()
function.This allows usage outside of
<Image>
, such as:background-image
orimage-set
context.drawImage()
or simplynew Image()
<picture>
media queries to implement Art Direction or Light/Dark Mode imagesExample