How to change all :root variables with one function

Viewed 420

Similar question : But can't able to get answer

Can be answer to this question : But has to split on each :

If possible to get all variable in one function and change each values

If there are 2-4 variable than easy to change but when that change to 10 or more

var root = document.querySelector(':root');

function func() {
  root.style.setProperty('--r', 'brown');
  root.style.setProperty('--b', 'lightblue');
  root.style.setProperty('--g', 'lightgreen');
}
:root {
  --r: red;
  --b: blue;
  --g: green;
}

.text1 {
  color: var(--r)
}

.text2 {
  color: var(--b)
}

.text3 {
  color: var(--g)
}
<div class="text1">Hello</div>
<div class="text2">Bye</div>
<div class="text3">World</div>
<button onclick="func()">Change</button>

Is there a way to automatic(dynamically) get all the variables without writing each variable while values array is self entered

var root = document.querySelector(':root');
var roots = getComputedStyle(root);
var re = roots.getPropertyValue('--r')
var bl = roots.getPropertyValue('--b')
var gr = roots.getPropertyValue('--g')


function func() {
  root.style.setProperty('--r', 'brown');
  root.style.setProperty('--b', 'lightblue');
  root.style.setProperty('--g', 'lightgreen');
}

function func2() {
  root.style.setProperty('--r', re);
  root.style.setProperty('--b', bl);
  root.style.setProperty('--g', gr);
}
:root {
  --r: red;
  --b: blue;
  --g: green;
}

.text1 {
  color: var(--r)
}

.text2 {
  color: var(--b)
}

.text3 {
  color: var(--g)
}
<div class="text1">Hello</div>
<div class="text2">Bye</div>
<div class="text3">World</div>
<button onclick="func()">Change</button>
<button onclick="func2()">Orignal</button>

But when getting back to original values then each value is entered by separate variable and for each it is defined .
Is there a way to have a approach which takes original values and variables in separate array automatically.

Thanks for help in advance

5 Answers

I understand you want to first read all the declared variables from the css and store them, so they might be resetted after applying new values? This code will do this, given that there's just one ':root' declaration in one stylesheet (easily complemented in case 'splitted' declaration in more places needed)

let variableLookup = {
  '--r': {
    newValue: 'teal'
  },
  '--b': {
    newValue: 'orange'
  },
  '--g': {
    newValue: 'purple'
  }
}

var root = document.querySelector(':root');

function setNewColors() {

  const cssText = [...document.styleSheets]
    .map(styleSheet => [...styleSheet.cssRules]
      .filter(CSSStyleRule => CSSStyleRule.selectorText === ':root'))
    .flat()[0].cssText

  // cssText = ':root { --r: red; --b: blue; --g: green; }'  

  cssText.match(/{(.*)}/)[1].trim()
    .split(';')
    .filter(Boolean)
    .forEach(declaration => {
      const [variable, oldValue] = declaration.split(':').map(str => str.trim())
      let entry = variableLookup[variable]
      if (entry) entry.oldValue = oldValue
    })

  console.log('variableLookup >>', variableLookup)

  Object.entries(variableLookup).forEach(([variable, {newValue}]) => {
    root.style.setProperty(variable, newValue);
  })
}

function resetColors() {
  Object.entries(variableLookup).forEach(([variable, {oldValue}]) => {    
    if (oldValue) root.style.setProperty(variable, oldValue)
  })
}
:root {
  --r: red;
  --b: blue;
  --g: green;
}

.text1 {
  color: var(--r)
}

.text2 {
  color: var(--b)
}

.text3 {
  color: var(--g)
}

:root {
  --c: magenta;
}
<div class="text1">Hello</div>
<div class="text2">Bye</div>
<div class="text3">World</div>
<button onclick="setNewColors()">Change to new colors</button>
<button onclick="resetColors()">Reset old colors</button>

Since the OP is interested in a version without using .split() these could be replaced by using a regex and .match()

const declarations = '--r: red; --b: blue; --g: green;'  

const regex1 = /^[\w-:\s]+(?=;)|(?<=;)[\w-:\s]+/g 

const declarationsArr = declarations.match(regex1)

console.log(declarationsArr)  // ["--r: red", " --b: blue", " --g: green"]

const regex2 = /[\w-]+(?=:)|(?<=:\s)[\w-]+/g

const declarationsSplit = declarationsArr.map(d => d.match(regex2))

console.log(declarationsSplit)  // [["--r", "red"], ["--b", "blue"], ["--g", "green"]]

One method can be entering all variables and values in different arrays and fetching values from them . Where variables = values which need to be equal have same index number

var root = document.querySelector(':root');

variable = ['--r', '--b', '--g'];
values = ['violet', 'lightblue', 'lightgreen']

function func() {
  for (let i = 0; i < 3; i++)
    root.style.setProperty(variable[i], values[i]);
}
:root {
  --r: red;
  --b: blue;
  --g: green;
}

.text1 {
  color: var(--r)
}

.text2 {
  color: var(--b)
}

.text3 {
  color: var(--g)
}
<div class="text1">Hello</div>
<div class="text2">Bye</div>
<div class="text3">World</div>
<button onclick="func()">Change</button>

Try this example.

  1. Initialize two arrays, one is empty for the current colors form the css and second for a new colors.
  2. Need to define how many variables, then get them and put in an empty array.
  3. Create two functions with loops, in the first we assign the new colors for variables, in the second reset.
const root = document.body;
// Colors arrays
const cssVarColors = [];
const newColors = ['brown', 'lightblue', 'lightgreen'];

// Create an array of variable colors from css.
const cssRootArray = document.styleSheets[0].cssRules;
for (const i of cssRootArray) {
// Check, if :root in the css.
  if (i.selectorText.includes('root')) {
    const rootArrayLength = i.style.length;
    for (let j = 0; j < rootArrayLength; j++) {
     const key = i.style[j];
     // Create object { key/variable : value/color }
     const value = getComputedStyle(root).getPropertyValue(key);
     cssVarColors.push({[key]: value});
    }
  }
}

// We change colors, with variable keys and indexes.
function changeColor() {
  for (const i in cssVarColors) {
   const key = Object.keys(cssVarColors[i]);
    // Check, if newColor array don't have a color.
    if (!newColors[i]) {
      return;
    }
   root.style.setProperty(key, newColors[i]);
  }
  variables();
}

change.addEventListener('click', changeColor);

  const root = document.body;
  // Colors arrays
  const cssVarColors = [];
  const newColors = ['brown', 'lightblue', 'lightgreen'];

  // Create an array of colors from a css variables file.
  const cssRootArray = document.styleSheets[0].cssRules;
  for (const i of cssRootArray) {
    // Check, if :root in the css.
    if (i.selectorText.includes('root')) {
      const rootArrayLength = i.style.length;
      for (let j = 0; j < rootArrayLength; j++) {
        const key = i.style[j];
        // Create object { key/variable : value/color }
        const value = getComputedStyle(root).getPropertyValue(key);
        cssVarColors.push({
          [key]: value,
        });
      }
    }
  }

  // We change colors, with variable keys and indexes.
  function changeColor() {
    for (const i in cssVarColors) {
      const key = Object.keys(cssVarColors[i]);
      // Check, if newColor array don't have a color.
      if (!newColors[i]) {
        return;
      }
      root.style.setProperty(key, newColors[i]);
    }
    variables();
  }
  // Can't separate in loop by [key, value],
  // because key has a specific value.
  function resetColor() {
    for (const i in cssVarColors) {
      if (!newColors[i]) {
        return;
      }
      const key = Object.keys(cssVarColors[i]);
      const value = Object.values(cssVarColors[i]);
      root.style.setProperty(key, value);
    }
    variables();
  }
  // Change button
  change.addEventListener('click', changeColor);
  // Reset button
  reset.addEventListener('click', resetColor);

  // extra for view
  cssVarColors.forEach(clr => {
    const el = document.createElement('span');
    el.textContent = JSON.stringify(clr);
    document.getElementById('variables').appendChild(el);
  });
:root {
  --r: red;
  --b: blue;
  --g: green;
  --m: magenta;
  --black: black;
}

.text1 {
  color: var(--r);
}

.text2 {
  color: var(--b);
}

.text3 {
  color: var(--g);
}


/* Extra style */
body {
  display: grid;
  grid-template-columns: 50px 150px;
  grid-template-rows: auto;
}

section {
  grid-column: 1;
}

#variables {
  grid-column: 2;
  display: flex;
  flex-direction: column;
}

span:nth-of-type(1) {
  border: 5px solid var(--r);
}

span:nth-of-type(2) {
  border: 5px solid var(--b);
}

span:nth-of-type(3) {
  border: 5px solid var(--g);
}

span:nth-of-type(4) {
  border: 5px solid var(--m);
}

span:nth-of-type(5) {
  border: 5px solid var(--black);
}
<section>
  <div class="text1">Hello</div>
  <div class="text2">Bye</div>
  <div class="text3">World</div>
</section>
<div id="variables"></div>
<button id="change">Change</button>
<button id="reset">Reset</button>

const root = document.documentElement;

function changeVariables(...values) {
  const variables = ["--r", "--g", "--b"];
  for (const variable of variables) {
    root.style.setProperty(variable, values[variable.indexof(variables)]);
  }
}

//Simply execute function like this
changeVariables("#000", "#808080", "#FF0000");
  1. setting new-colors you want to change
  2. backup original-colors

Try the example bellow

var root    = document.querySelector(':root');
var $divEle = $("div[class^='text']");  // get all element with class starting with 'text'

var arrCssVar     = ['--r', '--b','--g'];
var backupOrgColor= {}
var newColor     = {'--r':'brown', '--b':'lightblue', '--g':'lightgreen'}; // ordering color what you want to change

// backup original colors
$divEle.map(function(i, v) {
  if(i < arrCssVar.length){
    var compStyle = getComputedStyle(this);
    // setting key/value pair to Obj
    backupOrgColor[arrCssVar[i]] = compStyle.getPropertyValue(arrCssVar[i]);
  }
});

// change color
function setNewColors() {
  arrCssVar.map(function (key, value) {
    //console.log(key + ": key :change: value : "+ newColor[key]);
    root.style.setProperty(key, newColor[key]);
  });
}

// reset original color
function resetColors() {
  arrCssVar.map(function (key, value) {
    //console.log(key + ": key :: value : "+ backupOrgColor[key]);
    root.style.setProperty(key, backupOrgColor[key]);
  });
}
:root {
  --r: red;
  --b: blue;
  --g: green;
}

.text1 {
  color: var(--r)
}

.text2 {
  color: var(--b)
}

.text3 {
  color: var(--g)
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="text1">Hello</div>
<div class="text2">Bye</div>
<div class="text3">World</div>
<button onclick="setNewColors()">Change</button>
<button onclick="resetColors()">Orignal</button>

Related