Different mobile and desktop images with Next.js image #21379
Replies: 12 comments 10 replies
-
Looking though the source-code (canary branch) I couldn't find any use of |
Beta Was this translation helpful? Give feedback.
-
Duplicate of this question: 19880 |
Beta Was this translation helpful? Give feedback.
-
I'm trying to do the same thing, render different images based on device width. In my case, I have a carousel and i would want to have images with different aspect ratios depending o the device's screen widths. For example: import Image from 'next/image'
import myStaticImage1 from 'src/images/img1.jpg'
import myStaticImage1Mobile from 'src/images/img1-mobile.jpg'
const Banner = () => {
const device = useDevice() // client side
return (
<Carousel>
<Image src={device === 'mobile' ? myStaticImage1Mobile : myStaticImage1} {... otherProps } />
<Image src={device === 'mobile' ? myStaticImage1Mobile : myStaticImage1} {... otherProps } />
</Carousel>
)
} Or something like that: import Image from 'next/image'
import myStaticImage1 from 'src/images/img1.jpg'
import myStaticImage1Mobile from 'src/images/img1-mobile.jpg'
const Banner = () => {
const device = useDevice() // client side
return (
<Carousel>
{device === 'mobile'
? <Image src={myStaticImage1Mobile} {... otherProps } />
: <Image src={myStaticImage1} {... otherProps } />
}
{device === 'mobile'
? <Image src={myStaticImage1Mobile} {... otherProps } />
: <Image src={myStaticImage1} {... otherProps } />
}
</Carousel>
)
} |
Beta Was this translation helpful? Give feedback.
-
I'd like to find a solution for this as well. As currently for example SSG pages don't know on initial build the device size I guess the logic needs to be placed inside of a Another good way would be enabling the position of the scaled images based on |
Beta Was this translation helpful? Give feedback.
-
Also interested in this |
Beta Was this translation helpful? Give feedback.
-
This seems like a fundamental of responsive design (which Next is supposed to be the king of) ... how is this not answered yet? |
Beta Was this translation helpful? Give feedback.
-
Any updates on this? |
Beta Was this translation helpful? Give feedback.
-
I'm also interested in this! |
Beta Was this translation helpful? Give feedback.
-
Likewise interested |
Beta Was this translation helpful? Give feedback.
-
This helped me to bypass this: const [width, setWidth] = useState<number>(0);
useEffect(() => {
function handleResize() {
setWidth(window.innerWidth)
}
window.addEventListener('resize', handleResize)
handleResize()
return () => {
window.removeEventListener('resize', handleResize)
};
});
// Then on your component:
<div className={terminalHeaderStyles.logoContainer}>
<Image src={width > 375 ? logo : littleLogo} alt='Jardin Binario logo' layout='responsive' />
</div> But also interested on the right approach for this implementation |
Beta Was this translation helpful? Give feedback.
-
Do you have any information - is it possible to pass image props for mobile devices into the component? |
Beta Was this translation helpful? Give feedback.
-
The solutions above do work, but do not satisfy all our requirements. So our code looks like this: We created a hook that takes a media query and returns const getMatches = (query: string): boolean => {
// Prevents SSR issues
if (typeof window !== 'undefined') {
return window.matchMedia(query).matches;
}
return false;
};
/**
* Returns true if the given media query matches.
* Returns undefined until the first render occured to prevent hydration errors.
* @param query A media query as string
* @returns
*/
export function useMediaQuery(query: string): boolean | undefined {
const [hasMatch, setHasMatches] = useState<boolean>(getMatches(query));
const [initialLoad, setInitialLoad] = useState(true);
useLayoutEffect(() => {
if (initialLoad) {
setInitialLoad(false);
}
}, []);
function handleChange() {
setHasMatches(getMatches(query));
}
useEffect(() => {
const matchMedia = window.matchMedia(query);
handleChange();
matchMedia.addEventListener('change', handleChange);
return () => {
matchMedia.removeEventListener('change', handleChange);
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [query]);
return initialLoad ? undefined : hasMatch;
} When using it you just have to make sure that you show both images on const ExampleComponent = ({}) => {
const isMobile = useMediaQuery(`(max-width: 767.98px)`);
return (
<>
{(!isMobile || isMobile === undefined) && (
<Image src="/desktop-image.jpg" alt="This is the desktop image" />
)}
{(isMobile || isMobile === undefined) && (
<Image src="/mobile-image.jpg" alt="This is the mobile image" />
)}
</>
);
}; We did not fully test this solution yet, but it is working for us and we didn't notice any flickering on the client. |
Beta Was this translation helpful? Give feedback.
-
I'm in the process of switching my site over to Next.js image. I often use different mobile and desktop images for design purposes. Using the picture element allows me to ship only one image over to the client. Is there a way I can accomplish the same thing with Image?
Beta Was this translation helpful? Give feedback.
All reactions