switch image based on light and dark mode doesn't work well ?
here i need to swap between 2 images based on theme mode
like if it light i need logo-1 but if it dark i need it to be logo-2
with using this code from below but no luck
import { unstable_getImgProps as getImgProps } from 'next/image'
export function Logo() {
const common = { alt: 'logo', width: 40, height: 30 }
const { props: { srcSet: dark } } = getImgProps({ ...common, src: '/images/logo/logo.webp' })
const { props: { srcSet: light , ...rest } } = getImgProps({ ...common, src: '/images/logo/logo-2.webp' })
return (
<picture>
<source
media="(prefers-color-scheme: dark)"
srcSet={dark} />
<source media="(prefers-color-scheme: light )" srcSet={light} />
<img {...rest} />
</picture>
)
}
it's working on dark mode if i swap between 2 images it just worked fine but no luck with light mode
it doesn't update at all if i switching between light and dark does anyone has similar issue and how i can fix it ?
22 Replies
On first glance, I only notice an extra space between light and ) but that's probably not the issue.
Best to debug it in the browser. What's the resulting HTML?
nothing and i confirm that toggling working corectly by debuging if theme is light or dark
on the other hand i was suspicious about (prefers-color-scheme ) but i make it working by adding this lines
export function Logos() {
const { setTheme, theme } = useTheme()
const common = { alt: 'logo' }
const { props: { srcSet: dark } } = getImgProps({ ...common, src: '/images/logo/logos.webp' })
const { props: { srcSet: light, ...rest } } = getImgProps({ ...common, src: '/images/logo/logos-2.webp' })
return (
<picture>
<source
srcSet={theme === 'dark'? dark : light} />
<img {...rest} width={0} height={0} sizes="100vw" style={{ width: "100%", height: "auto" }} /> </picture> ) } but it's not working corectly in first mount for a component and that's wrong i believe i'ts not ment to working like so if i need it to work then i should trigger toggle mode and hence will be working fine i guess in first mound of site it can't know what is theme or what but it's take much time and no one help me for bad to solve it
<img {...rest} width={0} height={0} sizes="100vw" style={{ width: "100%", height: "auto" }} /> </picture> ) } but it's not working corectly in first mount for a component and that's wrong i believe i'ts not ment to working like so if i need it to work then i should trigger toggle mode and hence will be working fine i guess in first mound of site it can't know what is theme or what but it's take much time and no one help me for bad to solve it
I've never used unstable_getImgProps. So you'll have to show me the resulting HTML in the browser for me to be of any help.
As an alternative: You can always go back and simply use two next/image elements and switch them with CSS.
the resulting html
"use two next/image elements and switch them with CSS."
i see this approach do u have an example to do so
Well, basically like that:
#image-b {
display: none;
}
@media (prefers-color-scheme: dark) {
#image-a {
display: none;
}
#image-b {
display: inline;
}
}
The difference between your first code and your second code is that in the first version you let HTML handle which image should be displayed. In the second version you let JavaScript make that determination. Hence, the first version is definitely perferable.
it dosen't work either
in global.css :
.image-b {
display: none;
}
@media (prefers-color-scheme: dark) {
.image-a {
display: none;
}
.image-b {
display: inline;
}
}
in my component :
<>
<Image
src="/images/logo/logo.webp"
alt='logo'
width = {40}
height={30}
className=" image-b "
/>
<Image src="/images/logo/logo.webp" alt='logo' width = {40} height={30} className="image-a" /> </>
<Image src="/images/logo/logo.webp" alt='logo' width = {40} height={30} className="image-a" /> </>
Just the toggle doesn't work, right? How do you toggle the color scheme?
In your browser's developer tools?
You're currently using the same src. So when you toggle, you see the same image again.
i'm using next/theme
export function ThemeToggle() {
const { setTheme, theme } = useTheme()
return (
<Button
variant="ghost"
size="icon"
onClick={() => setTheme(theme === "light" ? "dark" : "light")}
>
<Icons.sun
className="h-5 w-5 rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0"
aria-hidden="true"
/>
<Icons.moon
className="absolute h-5 w-5 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100"
aria-hidden="true"
/>
<span className="sr-only">Toggle theme</span>
</Button>
)
}
and wrap my html with
<Providers attribute="class" defaultTheme="system" enableSystem>
here is provider component
import { ThemeProvider as NextThemesProvider } from "next-themes"
import { type ThemeProviderProps } from "next-themes/dist/types"
import { TooltipProvider } from "@/components/ui/tooltip"
export function Providers({ children, ...props }: ThemeProviderProps) {
return (
<NextThemesProvider {...props}>
<TooltipProvider>{children}</TooltipProvider>
</NextThemesProvider>
)
}
and here is my tailwind config for that specific part
darkMode: ["class", '[data-mode="dark"]'],
you mean i should do this
<Image
src="/images/logo/logo.webp"
alt='logo'
width = {40}
height={30}
className=" image-b "
/>
<Image src="/images/logo/logo-2.webp" alt='logo' width = {40} height={30} className="image-a" /> yeah i did but i change it for something to test
<Image src="/images/logo/logo-2.webp" alt='logo' width = {40} height={30} className="image-a" /> yeah i did but i change it for something to test
Oh, I see. Then you're not basing your color-scheme on the user's color-scheme. next-themes seems to store the current theme in local storage. That's why prefers-color-scheme doesn't work. Because prefers-color-scheme is based on the user's OS color scheme setting.
So you can't use prefers-color-scheme and have to use useTheme like in your second version.
So either like in your second version, or like this:
const { setTheme, theme } = useTheme()
return theme === 'dark' ? (
<Image
src="/images/logo/logo.webp"
alt='logo'
width = {40}
height={30}
/>
) : (
<Image
src="/images/logo/logo-2.webp"
alt='logo'
width = {40}
height={30}
/>
)
yeah that what i think about in first time
prefers-color-scheme
not working
Yes, because prefers-color-scheme is based on the user's OS color scheme. next-themes' color scheme is based on its current value in local storage.
where i can read about that
also this approach same as
srcSet={theme === 'dark'? dark : light}
and in first rendring it can never tell if i'm in dark or light
What exactly is unclear? You can check out next-themes source code. prefers-color-scheme is explained here: https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme
prefers-color-scheme - CSS: Cascading Style Sheets | MDN
The prefers-color-scheme CSS media feature is used to detect if a user has requested light or dark color themes.
A user indicates their preference through an operating system setting (e.g. light or dark mode) or a user agent setting.
Yes, because prefers-color-scheme is based on the user's OS color scheme. i didn't get it right
give me ur twitter user i need to follow u
Also: It seems like you're using Tailwind's dark variant but don't have next-themes configured appropriately.
https://github.com/pacocoursey/next-themes#with-tailwind
Oh, nevermind
You did
My bad
I'm a read-only Twitter user haha
Feel free to message me here
i'm using an open source project in generall so i just tweak it up and just use what i need from deleting the rest
GitHub
GitHub - sadmann7/skateshop: An open source e-commerce skateshop bu...
An open source e-commerce skateshop build with everything new in Next.js 13. - GitHub - sadmann7/skateshop: An open source e-commerce skateshop build with everything new in Next.js 13.
thanx mate really apperciate that help
No problem. As mentioned, feel free to reach out if you have other questions.
thanx and for u to know what the last soluation i came up is :
let src
switch (resolvedTheme) {
case 'light':
src = '/images/logo/logo-2.webp'
break
case 'dark':
src = '/images/logo/logo.webp'
break
default:
src = theme === 'light'? '/images/logo/logo-2.webp' : '/images/logo/logo.webp'
break
}
return (
<Image src={src} alt='logo' width = {40} height={30} /> ) remove defaultTheme="system" enableSystem from <Providers attribute="class" defaultTheme="system" enableSystem>
<Image src={src} alt='logo' width = {40} height={30} /> ) remove defaultTheme="system" enableSystem from <Providers attribute="class" defaultTheme="system" enableSystem>