Reputation: 983
How do you get and set CSS custom properties (those accessed with var(…)
in the stylesheet) using JavaScript (plain or jQuery)?
Here is my unsuccessful try: clicking on the buttons changes the usual font-weight
property, but not the custom --mycolor
property:
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<style>
body {
--mycolor: yellow;
background-color: var(--mycolor);
}
</style>
</head>
<body>
<p>Let's try to make this text bold and the background red.</p>
<button onclick="plain_js()">Plain JS</button>
<button onclick="jQuery_()">jQuery</button>
<script>
function plain_js() {
document.body.style['font-weight'] = 'bold';
document.body.style['--mycolor'] = 'red';
};
function jQuery_() {
$('body').css('font-weight', 'bold');
$('body').css('--mycolor', 'red');
}
</script>
</body>
</html>
Upvotes: 97
Views: 50435
Reputation: 9314
Answers involving getPropertyValue()
are the correct ones if you want the raw string value of the variable. However, this raw string value:
"calc(1px + 1px)"
instead of "2px"
.If you need calc evaluation and/or unit normalization, here is a hack that will always give you pixels:
function evaluateCssLength(lengthExpr, contextElem) {
// getComputedStyle(…).getPropertyValue(…) returns the raw expression for a CSS calc value,
// i.e. a string of the form "calc(…)"
//
// To evaluate the calc, we create a temporary element and give it a max-width, which is a CSS
// property that (1) expects a length and (2) will always resolve to the same actual pixel value
// regardless of its containing element and surrounding CSS. We read the max-width back, now
// computed and expressed as pixels, then discard the element.
const measureElem = document.createElement("div");
contextElem.appendChild(measureElem);
measureElem.style.maxWidth = lengthExpr;
const length = parseFloat(getComputedStyle(measureElem).maxWidth);
contextElem.removeChild(measureElem);
return length;
}
Use it as follows:
const containerElem = document.querySelect(".whatever");
// All the following will return pixels expressed as a float:
evaluateCssLength("37em", containerElem)
evaluateCssLength("var(--some-property)", containerElem)
evaluateCssLength("calc(100vh - 17ex * var(-foo))", containerElem)
Upvotes: 0
Reputation: 1121
You can use getComputedStyle function to get css variables,Here is a example.
const colors = document.querySelectorAll(".color");
const result = document.getElementById("result");
colors.forEach((color) => color.addEventListener("click", changeColor));
function changeColor(event) {
const target = event.target;
// get color
const color = getComputedStyle(target).getPropertyValue("--clr");
document.body.style.backgroundColor = color;
// active color
colors.forEach((color) => color.classList.remove("active"));
target.classList.add("active");
result.textContent = getComputedStyle(target).getPropertyValue("--clr")
}
result.textContent = "#1dd1a1";
body{
background-color: #1dd1a1;
}
.colors{
position: absolute;
padding: 2rem;
display: flex;
gap: 1rem;
}
.color{
display: inline-block;
width: 2rem;
height: 2rem;
background-color: var(--clr);
border-radius: 50%;
cursor: pointer;
transition: $time-unit;
}
.color.active{
border: .2rem solid #333;
transform: scale(1.25);
}
<h1>Click to change Background</h1>
<section class="colors">
<span class="color active" style="--clr: #1dd1a1"></span>
<span class="color" style="--clr: #ff6b6b"></span>
<span class="color" style="--clr: #2e86de"></span>
<span class="color" style="--clr: #f368e0"></span>
<span class="color" style="--clr: #ff9f43"></span>
</section>
Current Color: <span id="result"></span>
Upvotes: 2
Reputation: 4222
You can use document.body.style.setProperty('--name', value);
:
var bodyStyles = window.getComputedStyle(document.body);
var fooBar = bodyStyles.getPropertyValue('--foo-bar'); //get
document.body.style.setProperty('--foo-bar', newValue);//set
Upvotes: 108
Reputation: 8670
The standard methods to get/set CSS3 variables are .setProperty()
and .getPropertyValue()
.
If your Variables are Globals (declared in :root
), you can use the following, for getting and setting their values.
// setter
document.documentElement.style.setProperty('--myVariable', 'blue');
// getter
document.documentElement.style.getPropertyValue('--myVariable');
However the getter will only return the value of a var, if has been set, using .setProperty()
.
If has been set through CSS declaration, will return undefined
. Check it in this example:
let c = document.documentElement.style.getPropertyValue('--myVariable');
alert('The value of --myVariable is : ' + (c?c:'undefined'));
:root{ --myVariable : red; }
div{ background-color: var(--myVariable); }
<div>Red background set by --myVariable</div>
To avoid that unexpected behavior you have to make use of the getComputedStyle()
method , before calling .getPropertyValue()
.
The getter will then, look like this:
getComputedStyle(document.documentElement,null).getPropertyValue('--myVariable');
In my opinion, accessing CSS variables should be more simple, fast, intuitive and natural...
I've implemented CSSGlobalVariables
a tiny (<3kb) javascript helper which automatically detects and packs into an Object all the active CSS global variables in a document, for easier access & manipulation.
// get the document CSS global vars
let cssVar = new CSSGlobalVariables();
// set a new value to --myVariable
cssVar.myVariable = 'red';
// get the value of --myVariable
console.log( cssVar.myVariable );
Any change applied to the Object properties, is translated automatically to the CSS variables.
Available in : https://github.com/colxi/css-global-variables
Upvotes: 55
Reputation: 3832
The following example illustrates how one may change the background using either JavaScript or jQuery, taking advantage of custom CSS properties known also as CSS variables (read more here). Bonus: the code also indicates how one may use a CSS variable to change the font color.
function plain_js() {
// need DOM to set --mycolor to a different color
d.body.style.setProperty('--mycolor', 'red');
// get the CSS variable ...
bodyStyles = window.getComputedStyle(document.body);
fontcolor = bodyStyles.getPropertyValue('--font-color'); //get
// ... reset body element to custom property's new value
d.body.style.color = fontcolor;
d.g("para").style["font-weight"] = "bold";
this.style.display="none";
};
function jQuery_() {
$("body").get(0).style.setProperty('--mycolor','#f3f');
$("body").css("color",fontcolor);
$("#para").css("fontWeight","bold");
$(this).css("display","none");
}
var bodyStyles = null;
var fontcolor = "";
var d = document;
d.g = d.getElementById;
d.g("red").addEventListener("click",plain_js);
d.g("pink").addEventListener("click",jQuery_);
:root {
--font-color:white;
--mycolor:yellow;
}
body {
background-color: var(--mycolor);
color:#090;
}
#para {
font: 90% Arial,Helvetica;
font-weight:normal;
}
#red {
background:red;
}
#pink {
background:#f3f;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<p id="para">Let's try to make the background red or pink and change the text to white and bold.</p>
<button id="red">Red</button>
<button id="pink">Pink</button>
Note that with jQuery, in order to set the custom property to a differnt value, this response actually holds the answer. It uses the body element's get() method which allows access to the underlying DOM structure and returns the body element, thereby facilitating the code setting the custom property --mycolor
to a new value.
Upvotes: 6