CSS variables are not working on body tag while implementing a dark/light theme

Viewed 80

I am developing two themes for my site (light and dark), the site is developed in React. In the main CSS file I have inserted the colors that should be used in the light theme and in the dark theme, like this:

#light{
--color-bg: #4e4f50; /* #1f1f38 */
--color-bg-variant: #746c70; /* #2c2c6c */
--color-primary: #e2ded0; /* #4db5ff */
--color-primary-variant: #647c90; /* rgba(77, 181, 255, 0.4) */
--color-white: white;
--color-light: rgb(255 255 255 / 60%);
}

#dark{
--color-bg: #1A1A2E; /* #1f1f38 */
--color-bg-variant: #16213E; /* #2c2c6c */
--color-primary: #E94560; /* #4db5ff */
--color-primary-variant: #0F3460; /* rgba(77, 181, 255, 0.4) */
--color-white: white;
--color-light: rgb(255 255 255 / 60%);
}

These variables are read throughout the project apparently except in the CSS of the body tag which is like this:

body {
font-family: Poppins, sans-serif;
background: var(--color-bg);
color: var(--color-white);
line-height: 1.7; /* distanza tra le macroaree */
background-image: none;
}

Rightly, not working, there are all colors, except the background one, so the problem is not ignorable. I don't understand why in all the other CSS the variables are read but not from the body tag.

Here is how I use and change the theme from light to dark and vice versa (App.jsx):

import { createContext } from "react"
import { useState } from "react"

export const ThemeContext = createContext(null)

const App = () => {
const [theme, setTheme] = useState("dark")

const toggleTheme = () => {

setTheme((curr) => (curr === "light" ? "dark" : "light"))
}
return (
<ThemeContext.Provider value={{theme, setTheme}}>
  <Router>
      <Routes>
        <Route path="/" element={
          <div id={theme}>
            <Header/>
            <Nav/>
            <About/>
            <Experience/>
            <Services/>
            <BlogPreview/>
            <Contact/>
            <Footer/>
          </div>}
        />
        <Route path="/Blog" element={
          <div id={theme}>
            <Blog/>
            <NavG/>
          </div>}  
        />
        <Route path="*" element={
          <div id={theme}>
            <Error/>
            <NavGG/>
          </div>
        }/>
        <Route path="/Blog/buymeanr6please" element={
          <div id={theme}>
            <Post1/>
          </div>
        }/>
      </Routes>
  </Router>
</ThemeContext.Provider>
)
}

export default App

I hope I have explained myself well. Could someone give me a hand?

2 Answers

This is a cascading and inheritance issue. Those CSS variables of yours are defined in the context of that <div id={theme}>, which is a child of body, so body can't see them.

Either move the property from body to <div id={theme}>, like so:

#dark, #dark{
 font-family: Poppins, sans-serif;
 background: var(--color-bg);
 color: var(--color-white);
 line-height: 1.7; /* distanza tra le macroaree */
 background-image: none;
}

Or sets your variables on html so every child including body can see them. If you decide to do it this way, add the below code in App.jsx and remove the id from <div id={theme}>.

useEffect(() => {
   document.documentElement.setAttribute("id", theme);
}, [theme]);

First of all, use class names (start with dot) instead of Id's (start with #) cause element must have only unique ID's, and you need to change those based on user preference or clicked a toggle button.

.light{
  ...// your light colors
}

.dark{
  ...// your dark colors
}

Then use one of these classes on html element so body would inherit those variables.

Related