Home > OS >  How do I use my existing toggle to also switch between two css sheets?
How do I use my existing toggle to also switch between two css sheets?

Time:09-10

I am trying to implement a light mode/dark mode toggle on a website. The toggle itself is working as expected, but I can't figure out how to also make it switch between style sheets. I am new to JS so the CSS/HTML is there, but I can't get the script right.

So this is what I have so far that works on its own before trying to switch style sheets...

CSS:

<head>
<link rel="stylesheet" type="text/css" href="light-styles.css" id="theme-link">
</head>

<style>

/* Light Mode / Dark Mode Switch */

#switchposition { 
  position: relative; 
  display: flex; 
  flex-direction: 
  column-reverse; 
  justify-content: start; 
  align-items: start;
}

#modelabel { 
  position: relative; 
  font-size: 14px; 
  color: #dc92b9; 
  transition: .4s; 
  margin-bottom: 0; 
  padding-bottom: 0; 
}

.switch { 
  position: relative; 
  width: 50px; 
  height: 25px; 
}

.switch input { 
  opacity: 0;
  height: 0; 
  width: 0; 
}

.slider { 
  top: 0; 
  bottom: 0; 
  left: 0; 
  right: 0;
  transition: 0.4s;
  background-color: #dc92b9;
  border-radius: 34px;
  position: absolute;
  cursor: pointer; 
}

.slider::before { 
  content: ''; 
  position: absolute; 
  background-color: #f8e8ef;
  width: 15px;
  height: 15px; 
  border-radius: 50%;
  left: 5px; 
  bottom: 5px; 
  transition: 0.4s; 
}

.switch input:checked   .slider::before { 
  transform: translateX(25px); 
  background-color: #6d5f94; 
}

.switch input:checked   .slider { 
  background-color: #101010; 
}

</style>

HTML:

  <div id="switchposition">
    <p id="modelabel">Light Mode</p>
    <label >
        <input onclick="toggle()" type="checkbox" id="checkBox">
        <span ></span>
    </label>
  </div>

JS:

function toggle(){
    var input = document.getElementById("checkBox");
    if(input.checked == true){
        modelabel.style.color ="#6d5f94";
    } else{
        modelabel.style.color ="#dc92b9";
    }

    var x = document.getElementById("modelabel");
  if (x.innerHTML === "Light Mode") {
    x.innerHTML = "Dark Mode";
  } else {
    x.innerHTML = "Light Mode";
  }
  
}

This is what I tried to put into the code to also make it switch between css sheets. When I add this in nothing breaks, but it does not work either.

function toggle(){
    var input = document.getElementById("checkBox");
    if(input.checked == true){
        modelabel.style.color ="#6d5f94";
    } else{
        modelabel.style.color ="#dc92b9";
    }

    var input = document.getElementById("theme-link")
    if (input.checked == true) { 
        theme.setAttribute('href', 'dark-styles.css'); 
    } else { 
        theme.setAttribute('href', 'light-styles.css'); 
    } 

    var x = document.getElementById("modelabel");
  if (x.innerHTML === "Light Mode") {
    x.innerHTML = "Dark Mode";
  } else {
    x.innerHTML = "Light Mode";
  }
  
}

CodePudding user response:

Obviously you need to do some css groundwork first. Defining ALL your themes in one file works for me. What will differentiate the styles would be a class to the body of the document. Then on JS all you need to do is toggle the class (say dark) with the body.

Something like this:

var darkMode = false

function handle_dark_click() {
  if (darkMode == true) {
    document.body.classList.remove("dark");
  } else {
    document.body.classList.add("dark");
  }
  darkMode = !darkMode;
}

document.getElementById('toggle-theme').addEventListener('click', handle_dark_click)
/* default theme */

body {
  background: white;
  text-align: center;
}

h1 {
  color: blue;
}

h2 {
  color: navy;
}

div {
  border: 1px solid black;
}


/* another theme */

body.dark {
  background: #333;
}

body.dark h1 {
  color: lightgreen;
}

body.dark h2 {
  color: green;
}

body.dark div {
  border: 1px solid white;
}
<body>

  <div>
    <h1>hello world</h1>
    <h2>javascript</h2>
  </div>

  <br>
  <button id="toggle-theme">toggle theme</button>

</body>

CodePudding user response:

The easiest method would be to determine the theme based on HTML data attribute, then check which theme is applied in the CSS using html[data-theme='dark'] or html[data-theme='light'].

This can be broken down into several steps:

Apply Styles Based on Data Attribute

You can apply CSS to any given element by targetting data values. In this instance, you'd probably want to apply this value to an upper-most node, like <html>.

In JavaScript, you can change this value with:

document.getElementsByTagName('html')[0].setAttribute('data-theme', 'dark');

Which will update the HTML to look like:

<html data-theme="dark">
...
</html>

That can then be targeted in CSS with:

html[data-theme='light'] {
  --background: #fff;
  --foreground: #000;
}

html[data-theme='dark'] {
  --background: #000;
  --foreground: #fff;
}


Store User Preference

When the user changes theme, store their choice in the browsers local storage, using Window.localStorage, then apply it again next time they visit your site.

// Set
window.localStorage.setItem('theme', 'dark');
// Get
const theme = window.localStorage.theme;

Here's a more detailed tutorial.


Detect User Light / Dark Preference

You can check if the user's OS / browser is set to prefer light or dark mode, and apply that theme on initial page load. This is done using prefers-color-scheme

@media (prefers-color-scheme: dark) {
  --background: #000;
  --foreground: #fff;
}

@media (prefers-color-scheme: light) {
  --background: #fff;
  --foreground: #000;
}

Putting it all Together

Here's a live example, which combines the above points into a runnable code snippet, which you can integrate into your app

const setTheme = () => {
  const newTheme = document.getElementById('theme-selector').value;
  const htmlTag = document.getElementsByTagName('html')[0];
  if (htmlTag.hasAttribute('data-theme')) htmlTag.removeAttribute('data-theme');
  htmlTag.setAttribute('data-theme', newTheme);
  window.localStorage.setItem('theme', newTheme);
}

// Apply previously saved theme, on page load
document.onload = function() {
  const savedTheme = window.localStorage.theme;
  if (savedTheme) {
    document.getElementsByTagName('html')[0].setAttribute('data-theme', savedTheme)
  }
};
html[data-theme='light'] {
  --background: #fff;
  --foreground: #000;
}

html[data-theme='dark'] {
  --background: #000;
  --foreground: #fff;
}


body {
  background: var(--background);
  color: var(--foreground);
}
<label for="theme-selector">Theme</label>
<select id="theme-selector" onchange="setTheme()">
  <option value="light">Light</option>
  <option value="dark">Dark</option>
</select>

If you want to see a real-world example, of how this could scale up for larger code bases, I am using this approach in this app, and the theming is explained in this docs

  • Related