Reputation: 4262
Alright, I'm creating a system for my webpage that allows users to change the theme. How I want to accomplish this is by having all the colors as variables, and the colors are set in the :root part of the CSS.
What I want to do is change those colors via JavaScript. I looked up how to do it, but nothing that I attempted actually worked properly. Here's my current code:
CSS:
:root {
--main-color: #317EEB;
--hover-color: #2764BA;
--body-color: #E0E0E0;
--box-color: white;
}
JS:
(Code to set the theme, it's ran on the click of a button) - I didn't bother adding the :root change to the other 2 themes since it doesn't work on the Dark theme
function setTheme(theme) {
if (theme == 'Dark') {
localStorage.setItem('panelTheme', theme);
$('#current-theme').text(theme);
$(':root').css('--main-color', '#000000');
}
if (theme == 'Blue') {
localStorage.setItem('panelTheme', 'Blue');
$('#current-theme').text('Blue');
alert("Blue");
}
if (theme == 'Green') {
localStorage.setItem('panelTheme', 'Green');
$('#current-theme').text('Green');
alert("Green");
}
}
(Code that is ran when the html is loaded)
function loadTheme() {
//Add this to body onload, gets the current theme. If panelTheme is empty, defaults to blue.
if (localStorage.getItem('panelTheme') == '') {
setTheme('Blue');
} else {
setTheme(localStorage.getItem('panelTheme'));
$('#current-theme').text(localStorage.getItem('panelTheme'));
}
}
It shows the alert, but does not actually change anything. Can someone point me in the right direction?
Upvotes: 137
Views: 160000
Reputation: 403
We can use the registerProperty() using the @property CSS at-rule.
window.CSS.registerProperty({
name: "--my-color",
syntax: "<color>",
inherits: false,
initialValue: "#c0ffee",
});
Upvotes: 0
Reputation: 392
private switchDarkMode = (value: boolean) => {
let darkStyles = document.getElementById("darkStyles");
if (!darkStyles) {
darkStyles = domConstruct.create(
"style",
{
id: "darkStyles",
},
document.head
);
}
darkStyles.innerHTML = `
:root {
--white: ${!value ? "white" : "black"};
};
`;
}
Upvotes: 0
Reputation: 144
If you want to target the stylesheet you can do this:
const styleSheet = document.styleSheets[0]
const ruleIndex = [...styleSheet.cssRules].findIndex(rule => rule.cssText.includes('--sidebar:'))
const ruleText = styleSheet.cssRules[ruleIndex].cssText
let newRule: string
if (isOpen()) newRule = ruleText.replace('--sidebar: var(--sidebar-open)', '--sidebar: var(--sidebar-closed)')
else newRule = ruleText.replace('--sidebar: var(--sidebar-closed)', '--sidebar: var(--sidebar-open)')
styleSheet.deleteRule(ruleIndex)
styleSheet.insertRule(newRule, ruleIndex)
Just be sure that the string to replace is exactly the same as in your stylesheet, including spaces;
CSS:
:root {
--sidebar: var(--sidebar-open);
--sidebar-open: 15rem;
--sidebar-closed: 2rem;
}
Text to teplace:
Works:
--sidebar: var(--sidebar-open)
Doesn't works (One space is missing):
--sidebar:var(--sidebar-open)
The answer from @Michael works, but it adds a new rule every time you switch the style.
Upvotes: 0
Reputation: 31
As per the answer of DEV Tiago França, which worked on my case. here is why it works like a charm:
/* Root original style */
:root {
--hl-color-green: green;
}
/* Using * overrides the variable for all html tags where it is actually used */
* {
--hl-color-green: #0cc120;
}
Upvotes: 0
Reputation: 1696
/*My style*/
:root {
--hl-color-green: green;
}
/*My update*/
* {
--hl-color-green: #0cc120;
}
Upvotes: -2
Reputation: 2939
I think this is cleaner and easier to remember.
to set/get css variables to/from :root
const root = document.querySelector(':root');
// set css variable
root.style.setProperty('--my-color', 'blue');
// to get css variable from :root
const color = getComputedStyle(root).getPropertyValue('--my-color'); // blue
Example: setting multiple variables all at once
const setVariables = vars => Object.entries(vars).forEach(v => root.style.setProperty(v[0], v[1]));
const myVariables = {
'--color-primary-50': '#eff6ff',
'--color-primary-100': '#dbeafe',
'--color-primary-200': '#bfdbfe',
'--color-primary-300': '#93c5fd',
'--color-primary-400': '#60a5fa',
'--color-primary-500': '#3b82f6',
'--color-primary-600': '#2563eb',
'--color-primary-700': '#1d4ed8',
'--color-primary-800': '#1e40af',
'--color-primary-900': '#1e3a8a',
};
setVariables(myVariables);
Upvotes: 32
Reputation: 3259
TL;DR
A solution to the problem could be the below code:
const headTag = document.getElementsByTagName('head')[0];
const styleTag = document.createElement("style");
styleTag.innerHTML = `
:root {
--main-color: #317EEB;
--hover-color: #2764BA;
--body-color: #E0E0E0;
--box-color: white;
}
`;
headTag.appendChild(styleTag);
Explanation:
Although @Daedalus answer with document.documentElement
does the job pretty well, a slightly better approach is to add the styling into a <style>
HTML tag (solution proposed).
If you add document.documentElement.style
then all the CSS variables are added into the html
tag and they are not hidden:
On the other hand, with the proposed code:
const headTag = document.getElementsByTagName('head')[0];
const styleTag = document.createElement("style");
styleTag.innerHTML = `
:root {
--main-color: #317EEB;
--hover-color: #2764BA;
--body-color: #E0E0E0;
--box-color: white;
}
`;
headTag.appendChild(styleTag);
the HTML tag will be cleaner and if you inspect the HTML tag you can also see the :root
styling as well.
Upvotes: 6
Reputation: 13082
Read only, retrieve all CSS --root
rules in an array, without using .getComputedStyle()
.
This may allow to retrieve values before full DOM content load, to create modules that use global root theme variables, but not via CSS. (canvas context...)
/* Retrieve all --root CSS variables
* rules into an array
* Without using getComputedStyle (read string only)
* On this example only the first style-sheet
* of the document is parsed
*/
console.log(
[...document.styleSheets[0].rules]
.map(a => a.cssText.split(" ")[0] === ":root" ?
a.cssText.split("{")[1].split("}")[0].split("--") : null)
.filter(a => a !== null)[0]
.map(a => "--"+a)
.slice(1)
)
:root {
--gold: hsl(48,100%,50%);
--gold-lighter: hsl(48,22%,30%);
--gold-darker: hsl(45,100%,47%);
--silver: hsl(210,6%,72%);
--silver-lighter: hsl(0,0%,26%);
--silver-darker: hsl(210,3%,61%);
--bronze: hsl(28,38%,67%);
--bronze-lighter: hsl(28,13%,27%);
--bronze-darker: hsl(28,31%,52%);
}
Upvotes: 0
Reputation: 864
For those who want to modify the actual style sheet the following works:
var sheet = document.styleSheets[0];
sheet.insertRule(":root{--blue:#4444FF}");
More info at here: https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet/insertRule
Upvotes: 26
Reputation: 526
I came here looking how to toggle the :root
color-scheme with JavaScript, which sets the browser to dark mode (including the scroll bars) like this:
:root {
color-scheme: dark;
}
using the @Daedalus answer above, this is how I implemented my dark mode detection from user preference:
const userPrefersDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches;
const preferredTheme = userPrefersDarkMode ? 'dark' : 'light';
document.documentElement.style.setProperty("color-scheme", preferredTheme);
or with saved toggle:
const savedTheme = localStorage.getItem('theme');
if (savedTheme == 'dark') {
thisTheme = 'light'
}
else {
thisTheme = 'dark'; // the default when never saved is dark
}
document.documentElement.style.setProperty("color-scheme", thisTheme);
localStorage.setItem('theme', thisTheme);
see also the optional meta tag in the header:
<meta name="color-scheme" content="dark light">
Upvotes: 8
Reputation: 603
To use the values of custom properties in JavaScript, it is just like standard properties.
// get variable from inline style
element.style.getPropertyValue("--my-variable");
// get variable from wherever
getComputedStyle(element).getPropertyValue("--my-variable");
// set variable on inline style
element.style.setProperty("--my-variable", 4);
Upvotes: 8
Reputation: 659
old jquery magic still working too
$('#yourStyleTagId').html(':root {' +
'--your-var: #COLOR;' +
'}');
Upvotes: 2
Reputation: 4262
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!
Upvotes: 261