Get All Css Root Variables In Array Using Javascript And Change The Values
Solution 1:
this script will return an array of root variables in all stylesheets, served from the domain. Out of domain stylesheets are not accessible due to CORS policies.
Array.from(document.styleSheets)
.filter(
sheet =>
sheet.href === null || sheet.href.startsWith(window.location.origin)
)
.reduce(
(acc, sheet) =>
(acc = [
...acc,
...Array.from(sheet.cssRules).reduce(
(def, rule) =>
(def =
rule.selectorText === ":root"
? [
...def,
...Array.from(rule.style).filter(name =>
name.startsWith("--")
)
]
: def),
[]
)
]),
[]
);
Note: a root:
rule in a lower order stylesheet will override a parent root
rule.
Solution 2:
I needed a similar solution today. Here's a quick one on codepen.
// could pass in an array of specific stylesheets for optimization
function getAllCSSVariableNames(styleSheets = document.styleSheets){
var cssVars = [];
// loop each stylesheet
for(var i = 0; i < styleSheets.length; i++){
// loop stylesheet's cssRules
try{ // try/catch used because 'hasOwnProperty' doesn't work
for( var j = 0; j < styleSheets[i].cssRules.length; j++){
try{
// loop stylesheet's cssRules' style (property names)
for(var k = 0; k < styleSheets[i].cssRules[j].style.length; k++){
let name = styleSheets[i].cssRules[j].style[k];
// test name for css variable signiture and uniqueness
if(name.startsWith('--') && cssVars.indexOf(name) == -1){
cssVars.push(name);
}
}
} catch (error) {}
}
} catch (error) {}
}
return cssVars;
}
function getElementCSSVariables (allCSSVars, element = document.body, pseudo){
var elStyles = window.getComputedStyle(element, pseudo);
var cssVars = {};
for(var i = 0; i < allCSSVars.length; i++){
let key = allCSSVars[i];
let value = elStyles.getPropertyValue(key)
if(value){cssVars[key] = value;}
}
return cssVars;
}
var cssVars = getAllCSSVariableNames();
console.log(':root variables', getElementCSSVariables(cssVars, document.documentElement));
Solution 3:
You can declare an associative array with the keys as the node property with their values, then use a function to set your theme:
var primaryColor = document.documentElement.style.getPropertyValue('--primaryColor');
var secondaryColor = document.documentElement.style.getPropertyValue('--secondaryColor');
var errorColor = document.documentElement.style.getPropertyValue('--errorColor');
var themeColors = {}
themeColors["--primaryColor"] = primaryColor;
themeColors["--secondaryColor"] = secondaryColor;
themeColors["--errorColor"] = errorColor;
function setTheme(theme) {
for (key in theme) {
let color = theme[key];
document.documentElement.style.setProperty(key, color);
}
}
A working example I used with Atom and Bootstrap:
var backgroundColor = document.documentElement.style.getPropertyValue('--blue');
backgroundColor = "#dc3545";
function setTheme(theme) {
for (key in theme) {
let color = theme[key];
document.documentElement.style.setProperty(key, color);
}
}
var theme = {}
theme["--blue"] = backgroundColor;
setTheme(theme);
>>Edit<<
Nadeem clarified the question a bit better with a comment below, unfortunately however I've learned that :root
can be accessed with get Window.getComputedStyle()
however this doesn't return CSS Variable declarations.
A hack around this is just to read the css file, parse it for variables and stuff them into an associative array, but even this assumes you know where to get that css file...
//an associative array that will hold our values
var cssVars = {};
var request = new XMLHttpRequest();
request.open('GET', './css/style.css', true);
request.onload = function() {
if (request.status >= 200 && request.status < 400) {
//Get all CSS Variables in the document
var matches = request.responseText.match(/(--)\w.+;/gi);
//Get all CSS Variables in the document
for(let match in matches) {
var property = matches[match];
//split the Variable name from its value
let splitprop = property.split(":")
//turn the value into a string
let value = splitprop[1].toString()
cssVars[splitprop[0]] = value.slice(0, -1); //remove ;
}
// console.log(cssVars);
// > Object {--primaryColor: "aliceblue", --secondaryColor: "blue", --errorColor: "#cc2511"}
// console.log(Object.keys(cssVars));
// > ["--primaryColor", "--secondaryColor", "--errorColor" ]
setTheme(cssVars)
} else {
// We reached our target server, but it returned an error
}
};
request.onerror = function() {
console.log("There was a connection error");
};
request.send();
function setTheme(theme) {
var keys = Object.keys(theme)
for (key in keys) {
let prop = keys[key]
let color = theme[keys[key]];
console.log(prop, color);
// --primaryColor aliceblue etc...
}
}
Solution 4:
If you know all your variable will be placed inside the :root
and it's the first declaration in your first CSS file, you can try something like this and you will get all the variable inside an Object:
var declaration = document.styleSheets[0].cssRules[0];
var allVar = declaration.style.cssText.split(";");
var result = {}
for (var i = 0; i < allVar.length; i++) {
var a = allVar[i].split(':');
if (a[0] !== "")
result[a[0].trim()] = a[1].trim();
}
console.log(result);
var keys = Object.keys(result);
console.log(keys);
//we change the first variable
document.documentElement.style.setProperty(keys[0], 'green');
//we change the variable --secondary-color
document.documentElement.style.setProperty(keys[keys.indexOf("--secondary-color")], 'red');
:root {
--primary-color: aliceblue;
--secondary-color: blue;
--error-color: #cc2511
}
p {
font-size: 25px;
color: var(--primary-color);
border:1px solid var(--secondary-color)
}
<p>Some text</p>
Solution 5:
Here is another in typescript, where I continued work that RLoniello mentioned. It also outputs it as a JS object, that is converts --font-family: "Verdana" to fontFamily: "Verdana".
const CssKeyToJsKey = (key: string) =>
key.replace('--', '').replace(/-./g, (x) => x.toUpperCase()[1]);
const getAllCSSVariableNames = (styleSheets: StyleSheetList = document.styleSheets) => {
const cssVars = [];
Array.from(styleSheets).forEach((styleSheet) => {
Array.from(styleSheet.cssRules).forEach((rule) => {
if (!rule || !rule['style']) {
return;
}
Array.from(rule['style']).forEach((style: string) => {
if (style.startsWith('--') && cssVars.indexOf(style) == -1) {
cssVars.push(style);
}
});
});
});
return cssVars;
};
const getElementCSSVariables = (
allCSSVars: Array<string>,
element: HTMLElement = document.body,
pseudo: string | undefined = ''
) => {
const elStyles = window.getComputedStyle(element, pseudo);
const cssVars = {};
allCSSVars.forEach((key) => {
const value = elStyles.getPropertyValue(key);
if (value) {
cssVars[CssKeyToJsKey(key)] = value;
}
});
return cssVars;
};
export const getAllCSSVariables = (): Record<string, string> => {
const cssVars = getAllCSSVariableNames();
return getElementCSSVariables(cssVars, document.documentElement);
};
Post a Comment for "Get All Css Root Variables In Array Using Javascript And Change The Values"