最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Body CSS not updating with .setProperty() - Stack Overflow

programmeradmin5浏览0评论

I am trying to enable a dark mode/light mode feature on a website, in which I am using the .setProperty function to change the HEX value of a variable. However, whenever I toggle a switch, the site does not update. Why is this? Here is all the code pertaining to the issue:

let color = "#141414";

function changeMode() {
  
  console.log("Switch was toggled. Switching site color scheme...")
  
  let bg = document.querySelector(':root');
  
  // Should switch the value of 'color' from grey to white, and vice versa
  if (color === "#141414") { color = "#ffffff"; } else if (color === "#ffffff") {  color = "#141414"; }
  
  bg.style.setProperty("--main2", color);

}
:root {

  --main1: #ffdb15;
  --main2: #141414;

}

html, body {

  background-color: var(--main2);
  
}

.switch {
  position: relative;
  display: inline-block;
  width: 60px;
  height: 34px;
  left: 20px;
  top: 20px;

}

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

.slider {
  position: absolute;
  cursor: pointer;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: #ccc;
  -webkit-transition: .4s;
  transition: .4s;
}

.slider:before {
  position: absolute;
  content: "";
  height: 26px;
  width: 26px;
  left: 4px;
  bottom: 4px;
  background-color: white;
  -webkit-transition: .4s;
  transition: .4s;
}

input:checked + .slider {
  background-color: #5d00e2;
}

input:focus + .slider {
  box-shadow: 0 0 1px #5d00e2;
}

input:checked + .slider:before {
  -webkit-transform: translateX(26px);
  -ms-transform: translateX(26px);
  transform: translateX(26px);
}

.slider.round {
  border-radius: 34px;
}

.slider.round:before {
  border-radius: 50%;
}
<label class = "switch" onclick = "changeMode()">
  <input type = "checkbox" checked>
  <span class = "slider round"> </span>
</label>

I am trying to enable a dark mode/light mode feature on a website, in which I am using the .setProperty function to change the HEX value of a variable. However, whenever I toggle a switch, the site does not update. Why is this? Here is all the code pertaining to the issue:

let color = "#141414";

function changeMode() {
  
  console.log("Switch was toggled. Switching site color scheme...")
  
  let bg = document.querySelector(':root');
  
  // Should switch the value of 'color' from grey to white, and vice versa
  if (color === "#141414") { color = "#ffffff"; } else if (color === "#ffffff") {  color = "#141414"; }
  
  bg.style.setProperty("--main2", color);

}
:root {

  --main1: #ffdb15;
  --main2: #141414;

}

html, body {

  background-color: var(--main2);
  
}

.switch {
  position: relative;
  display: inline-block;
  width: 60px;
  height: 34px;
  left: 20px;
  top: 20px;

}

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

.slider {
  position: absolute;
  cursor: pointer;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: #ccc;
  -webkit-transition: .4s;
  transition: .4s;
}

.slider:before {
  position: absolute;
  content: "";
  height: 26px;
  width: 26px;
  left: 4px;
  bottom: 4px;
  background-color: white;
  -webkit-transition: .4s;
  transition: .4s;
}

input:checked + .slider {
  background-color: #5d00e2;
}

input:focus + .slider {
  box-shadow: 0 0 1px #5d00e2;
}

input:checked + .slider:before {
  -webkit-transform: translateX(26px);
  -ms-transform: translateX(26px);
  transform: translateX(26px);
}

.slider.round {
  border-radius: 34px;
}

.slider.round:before {
  border-radius: 50%;
}
<label class = "switch" onclick = "changeMode()">
  <input type = "checkbox" checked>
  <span class = "slider round"> </span>
</label>

Is the problem in the color variable, or in the program not updating the page's body itself when the value is switched?

Edit: Also, if you know of any way to improve my code, please let me know how. Specifically, is there any way to improve the method that switches the value of the color variable?

Share Improve this question asked May 20, 2021 at 1:14 BubblyBubbly 3013 silver badges12 bronze badges
Add a ment  | 

4 Answers 4

Reset to default 2

Have you noticed your event is being fired twice? You put your event listener on a label with an input checkbox inside. Clicking the label makes it like clicking the checkbox. So what you can do is change the onclick to be put in the input.

let color = "#141414";

function changeMode() {
  
  console.log("Switch was toggled. Switching site color scheme...")
  
  let bg = document.querySelector(':root');
  
  // Should switch the value of 'color' from grey to white, and vice versa
  if (color === "#141414") { 
    color = "#ffffff"; 
  } else if (color === "#ffffff") {  
    color = "#141414"; 
  }
  console.log(color);
  bg.style.setProperty("--main2", color);

}
:root {

  --main1: #ffdb15;
  --main2: #141414;

}

html, body {

  background-color: var(--main2);
  
}

.switch {
  position: relative;
  display: inline-block;
  width: 60px;
  height: 34px;
  left: 20px;
  top: 20px;

}

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

.slider {
  position: absolute;
  cursor: pointer;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: #ccc;
  -webkit-transition: .4s;
  transition: .4s;
}

.slider:before {
  position: absolute;
  content: "";
  height: 26px;
  width: 26px;
  left: 4px;
  bottom: 4px;
  background-color: white;
  -webkit-transition: .4s;
  transition: .4s;
}

input:checked + .slider {
  background-color: #5d00e2;
}

input:focus + .slider {
  box-shadow: 0 0 1px #5d00e2;
}

input:checked + .slider:before {
  -webkit-transform: translateX(26px);
  -ms-transform: translateX(26px);
  transform: translateX(26px);
}

.slider.round {
  border-radius: 34px;
}

.slider.round:before {
  border-radius: 50%;
}
<label class = "switch">
  <input type = "checkbox" checked onclick="changeMode()">
  <span class = "slider round"> </span>
</label>

If you look at the console while clicking the input you can see it's triggering two click events, effectively toggling it twice at once. You can add console.log(event) in changeMode() to see exactly what events are triggering (label click and the input click). The quick fix is to change it to trigger on the input change, rather than parent label click:

<label class = "switch">
   <input onchange="changeMode()" type = "checkbox" checked>
   <span class = "slider round"> </span>
</label>

Your question is actually asking How to update css variable with js?

Below is example

 <script>
// Get the root element
var r = document.querySelector(':root');

// Create a function for getting a variable value
function myFunction_get() {
  // Get the styles (properties and values) for the root
  var rs = getComputedStyle(r);
  // Alert the value of the --blue variable
  alert("The value of --blue is: " + rs.getPropertyValue('--blue'));
}

// Create a function for setting a variable value
function myFunction_set() {
  // Set the value of variable --blue to another value (in this case "lightblue")
  r.style.setProperty('--blue', 'lightblue');
}
</script> 

Add var rs = getComputedStyle(r); and it will work fine

source: w3school

You should use getComputedStyle to get the document.documentElement, then you can set the variable in a conditional and then set the style of the document.documentElement using setProperty.

There is a big difference between getComputedStyle(element).backgroundColor and element.style.backgroundColor. The first will actually give you the set CSS from the style sheet where as the latter will give you the inline style set in the elements HTML tag.

So you get the set style that is set using a variable in your CSS file using getComputedStyle(element) and then run that through your conditional and set the inline of the ROOT using element.style.backgroundColor where element is set to document.documentElement.

let bg = document.documentElement;
let input = document.getElementById('input')

function changeMode() { 
  let color = '';
  currentStyle = getComputedStyle(document.documentElement).backgroundColor
  currentStyle === "rgb(20, 20, 20)" ? color = "rgb(255, 219, 21)" : color = "rgb(20, 20, 20)"      
  bg.style.setProperty("--main2", color);
}

input.addEventListener('click', changeMode)
:root {
  --main1: #ffdb15;
  --main2: #141414;
}

html,
body {
  background-color: var(--main2);
}

.switch {
  position: relative;
  display: inline-block;
  width: 60px;
  height: 34px;
  left: 20px;
  top: 20px;
}

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

.slider {
  position: absolute;
  cursor: pointer;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: #ccc;
  -webkit-transition: .4s;
  transition: .4s;
}

.slider:before {
  position: absolute;
  content: "";
  height: 26px;
  width: 26px;
  left: 4px;
  bottom: 4px;
  background-color: white;
  -webkit-transition: .4s;
  transition: .4s;
}

input:checked+.slider {
  background-color: #5d00e2;
}

input:focus+.slider {
  box-shadow: 0 0 1px #5d00e2;
}

input:checked+.slider:before {
  -webkit-transform: translateX(26px);
  -ms-transform: translateX(26px);
  transform: translateX(26px);
}

.slider.round {
  border-radius: 34px;
}

.slider.round:before {
  border-radius: 50%;
}
<label class="switch">
  <input id="input" type="checkbox" checked>
  <span class="slider round"> </span>
</label>

发布评论

评论列表(0)

  1. 暂无评论