Get All CSS Root Variables in Array Using JavaScript and Change the Values

How to change all :root variables with one function

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>

How to change CSS :root color variables in JavaScript

Thank you @pvg for providing the link. I had to stare at it for a little to understand what was going on, but I finally figured it out.

The magical line I was looking for was this:

document.documentElement.style.setProperty('--your-variable', '#YOURCOLOR');

That did exactly what I wanted it to do, thank you very much!

Get an overview of all css variables set on root

Found the answer thanks to a post on SO. It reads the :root property from the stylesheet and loops through the properties looking for the -- keyword.

I wasn't a fan of all the filter function chaining, so I'll leave my own solution here.

/**
* Get all simpleResponse CSS variables on the root of the chat widget.
*/
function getCustomizableProperties(): string[] {

// Find the css sheet that includes the simpleResponse CSS settings.
const simpleResponseStylesheet = getSimpleResponseStyleSheet();

if (!simpleResponseStylesheet) {
console.debug('No customizable properties found. Skipping custom theme rendering.')
return [];
}

// Once found, collect the CSS settings and put them into an array.
const properties = getSimpleResponseStyleProperties(simpleResponseStylesheet);
return properties;
}

function getSimpleResponseStyleSheet(): CSSStyleSheet | undefined {
const styleSheets = Array.from(document.styleSheets);
const simpleResponseStylesheet = styleSheets.find(styleSheet => {

if (styleSheet.href === null) {
const cssRules = Array.from(styleSheet.cssRules);

return cssRules.find(rule => rule.cssText.includes('--simpleResponse'))
}
return undefined;
});

return simpleResponseStylesheet;
}

function getSimpleResponseStyleProperties(styleSheet: CSSStyleSheet): string[] {
const cssRules = Array.from(styleSheet.cssRules);

// Casting to any to access properties missing from typing.
const rootStyleRule: any = cssRules.find((cssRule) => {
const rule = cssRule as any;
return rule.selectorText === ':root';
})

const rootStyleProperties = Array.from(rootStyleRule.style) as string[];

return rootStyleProperties.filter(prop => prop.includes('--simpleResponse'));
}

This returns an array of CSS variables

0: "--simpleResponse-background-color"
1: "--simpleResponse-text-color"
2: "--simpleResponse-text-font"
3: "--simpleResponse-text-font-weight"
4: "--simpleResponse-text-font-size"

Change CSS root variable with jquery or javascript

You can do this pretty easy with something like:

document.documentElement.style.setProperty('--themeColor', 'red');

Update:
Not sure if the question was just about changing the color as I thought. Now I've also added a getRandomColor() example. Just to get random stuff can be a big load of work depending if you want to save the last used color by the user or so ...

// array with colorsvar colors = [  "red",  "green",  "lime",  "purple",  "blue"];
// get random color from arrayfunction getColor() { return colors[ Math.floor(Math.random() * colors.length) ];}
// Set the color from arraydocument.documentElement.style.setProperty('--themeColor', getColor());
:root {    --themeColor: orange;}
a { color: var(--themeColor)} div { width: 100px; height: 100px; background-color: var(--themeColor);}
<a href="#">Hello world</a><div>Test</div>

Access CSS variable from javascript

Just the standard way:

  1. Get the computed styles with getComputedStyle
  2. Use getPropertyValue to get the value of the desired property
getComputedStyle(element).getPropertyValue('--color-font-general');

Example:

var style = getComputedStyle(document.body)
console.log( style.getPropertyValue('--bar') ) // #336699
console.log( style.getPropertyValue('--baz') ) // calc(2px*2)
:root { --foo:#336699; --bar:var(--foo); --baz:calc(2px*2); }

List CSS custom properties (CSS Variables)

Update:

  • To catch CORS errors, I added !styleSheet.href && to the first if-statement.

One possible solution would be to parse the document.styleSheets, and then split the rules into properties/values

var allCSS = [].slice.call(document.styleSheets)
.reduce(function(prev, styleSheet) {
if (!styleSheet.href && styleSheet.cssRules) {
return prev + [].slice.call(styleSheet.cssRules)
.reduce(function(prev, cssRule) {
if (cssRule.selectorText == ':root') {
var css = cssRule.cssText.split('{');
css = css[1].replace('}','').split(';');
for (var i = 0; i < css.length; i++) {
var prop = css[i].split(':');
if (prop.length == 2 && prop[0].indexOf('--') == 1) {
console.log('Property name: ', prop[0]);
console.log('Property value:', prop[1]);
}
}
}
}, '');
}
}, '');
:root {
--bc: #fff;
--bc-primary: #eee;
--bc-secondary: #ddd;
}

Getting a calc() CSS variable into JavaScript

  • Problem was, you are access root values which returns string.
  • and calc() function cannot calculate multiplication of 100ms * 44 so, I have changed --loaderSpeed:100 removed ms. and also created new valiable called loaderSecondsMultiplier.
  • After that, I have getPropertyValue get css variables values and converted them into a number and then just mutiply them and in last store it in finalTimeout.

//GETTING DOCUMENT STYLES
let docStyle = getComputedStyle(document.documentElement);
// GEETING CSS VARIABLE VALUES
let loaderSpeed = parseInt(docStyle.getPropertyValue('--loaderSpeed'));
let loaderSecondsMultiplier = parseInt(docStyle.getPropertyValue('--loaderSecondsMultiplier'));
// MUTIPLYING AND STORING IT'S VALUE TO finalTimeout
let finalTimeout = loaderSpeed * loaderSecondsMultiplier;
setTimeout(() => {
const box = document.getElementById('loaderWrapper');
box.style.display = 'none';
}, finalTimeout);
:root {
--loaderSpeed: 100;
--loaderSecondsMultiplier: 44;
}
<div id="loaderWrapper">
<h1>hey</h1>
</div>

Updating a root css style through JavaScript

You can do something like,

document.documentElement.style.setProperty('--property', 'color');

You can visit this link for a demo created by wesbos.



Related Topics



Leave a reply



Submit