Changing the theme of a HTML-Page with JS document.styleSheets[0];

Viewed 30

this is my first question here.

I want to create a little dropdown to change the :root element in a CSS file.

function themechange(){
    var sheet = document.styleSheets[0];
    var theme = document.getElementById("theme-input").value;
    if (theme == 'Dark'){
        sheet.deleteRule(".root", 1);
        sheet.insertRule(":root{--m-background: #262626; --m-fontcolor: #ffffff; --m-boxcolor: #404040}", 1);
    }else{
    if (theme == 'Light'){
        sheet.deleteRule(".root", 1);
        sheet.insertRule(":root{--m-background: #ffffff; --m-fontcolor: #000000; --m-boxcolor: #acacac}", 1);
    }}
}
:root{
    --m-background: #ffffff;
    --m-fontcolor: #000000;
    --m-boxcolor: #acacac;
}
body{
    height: 100vh;
    display: flex;
    justify-content: center;
    align-items: center;
    background-color: var(--m-background);
    color: var(--m-fontcolor);
}
#box{
    height: 10rem;
    width: 15rem;
    background-color: var(--m-boxcolor);
    display: flex;
    justify-content: center;
    align-items: center;
}
<html lang="en">
<head>
    <title>Switch between Light- and Darktheme</title>
    <link rel="stylesheet" href="/style.css">
</head>
<body>
    <div id="box">
        <label for="input">Choose your Theme: </label>
        <select id="theme-input" onchange="themechange()">
            <script src="/app.js"></script>
            <datalist>
                <option value="Light">Light</option>
                <option value="Dark">Dark</option>
            </datalist>
        </select>
    </div>
    <span id="text">Text</span>
</body>
</html>

If you now open those, the first change works fine. But when you change from "Dark" to "Light" again, the CSS for "body" just gets deleted. The rest works just fine. At first I thought it's because the body tag is a name and not a div, because the #box works also just fine (the background color, not the font color).

I need to change the :root part because I don't see a different way for the main project.

Please help me. Thanks!

1 Answers

Don't go through all that code to directly modify the ::root. Simply add an attribute to your HTML element via Javascript.

If it is "checked" the value "dark" is added and the CSS variables for the dark mode are taken. As simple as that.

//GET THE CHECKBOX
const getChk = document.querySelector('.theme-input input[type="checkbox"]');

//REMEMBER CAMELCASE
function themeChange(e) {
    if (e.target.checked) {
    //Adding "data-theme" attr
        document.documentElement.setAttribute('data-theme', 'dark');
    }
    else {
        document.documentElement.setAttribute('data-theme', 'light');
    }    
}

getChk.addEventListener('change', themeChange, false);
:root {
  --m-background: #ffffff;
  --m-fontcolor: #000000;
  --m-boxcolor: #acacac;
}
/*JUST ADD THE DARK MODE VARS*/
[data-theme="dark"] {
  --m-background: #262626;
  --m-fontcolor: #ffffff;
  --m-boxcolor: #404040;
}

body {
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  background-color: var(--m-background);
  color: var(--m-fontcolor);
}

#box {
  height: 10rem;
  width: 15rem;
  background-color: var(--m-boxcolor);
  display: flex;
  justify-content: center;
  align-items: center;
}
<html lang="en">

<head>
  <title>Switch between Light- and Darktheme</title>
  <link rel="stylesheet" href="/style.css">
</head>

<body>
  <div id="box">
    <label class="theme-input" for="checkbox">Dark Mode?
    <input type="checkbox" id="checkbox" />
    </label>
  </div>
  <span id="text">Text</span>
</body>

</html>

And this version of your code with localStorage to detect and save the users theme when come back to your page:

(Won't work with the StackOverflow snippet for security reasons but here is the preview in JSFiddle).

//GET THE CHECKBOX
const getChk = document.querySelector('.theme-input input[type="checkbox"]');
//GET the current theme
const savedTheme = localStorage.getItem('theme') ? localStorage.getItem('theme') : null;

// Check the user preference
if (savedTheme) {
  document.documentElement.setAttribute('data-theme', savedTheme);

  if (savedTheme === 'dark') {
    getChk.checked = true;
  }
}

//REMEMBER CAMELCASE
function themeChange(e) {
  if (e.target.checked) {
    //Adding "data-theme" attr
    document.documentElement.setAttribute('data-theme', 'dark');
    //NOW adding localStorage to store user preference
    localStorage.setItem('theme', 'dark');
  } else {
    document.documentElement.setAttribute('data-theme', 'light');
    localStorage.setItem('theme', 'light');
  }
}

getChk.addEventListener('change', themeChange, false);
:root {
  --m-background: #ffffff;
  --m-fontcolor: #000000;
  --m-boxcolor: #acacac;
}


/*JUST ADD THE DARK MODE VARS*/

[data-theme="dark"] {
  --m-background: #262626;
  --m-fontcolor: #ffffff;
  --m-boxcolor: #404040;
}

body {
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  background-color: var(--m-background);
  color: var(--m-fontcolor);
}

#box {
  height: 10rem;
  width: 15rem;
  background-color: var(--m-boxcolor);
  display: flex;
  justify-content: center;
  align-items: center;
}
<html lang="en">

<head>
  <title>Switch between Light- and Darktheme</title>
  <link rel="stylesheet" href="/style.css">
</head>

<body>
  <div id="box">
    <label class="theme-input" for="checkbox">Dark Mode?
    <input type="checkbox" id="checkbox" />
    </label>
  </div>
  <span id="text">Text</span>
</body>

</html>

Related