David Richards
David Richards

Reputation: 1165

How do I edit a CSS variable using JS?

I have these CSS variables to control the colors of my project so I can do theming.

html {
    --main-background-image: url(../images/starsBackground.jpg);
    --main-text-color: #4CAF50;
    --main-background-color: rgba(0,0,0,.25);
    --beta-background-color: rgba(0,0,0,.85);
}

However no matter how I try to change the attribute(the two commented lines tried separately), the closest I get is returning not a valid attribute.

function loadTheme() {
    var htmlTag = document.getElementsByTagName("html");
    var yourSelect = document.getElementById( "themeSelect" );
    var selectedTheme = ( yourSelect.options[ yourSelect.selectedIndex ].value );
    // htmlTag[0].setAttribute('--main-text-color', '#FFCF40');
    // $("html").css("--main-text-color","#FFCF40");
}

the error message

Upvotes: 99

Views: 103908

Answers (8)

The ::placeholder selector is not available in javascript, however a walk around this, would be to declare a css variable in your style sheet, this variable would be available to the DOM and can be manipulated using javascript.

Example.

let root = document.querySelector(':root');
function setPlaceholderColor(){
root.style.setProperty('--placeholder', yellow);
}
:root{
  --placeholder: red;
}

input::placeholder{
  color: var(--placeholder)
}
<input type="text" placeholder ="Enter Name" onchange="setPlaceholderColor()" />

Upvotes: -1

Brett DeWoody
Brett DeWoody

Reputation: 62743

Turns out changing CSS variables is possible using the el.style.cssText property, or el.style.setProperty or el.setAttribute methods. In your code snippets el.setAttribute is incorrectly used, which is causing the error you encountered. Here's the correct way:

document.documentElement.style.cssText = "--main-background-color: red";

or

document.documentElement.style.setProperty("--main-background-color", "green");

or

document.documentElement.setAttribute("style", "--main-background-color: green");

Demo

The following demo defines a background color using a CSS variable, then changes it using the JS snippet 2 seconds after loading.

window.onload = function() {
  setTimeout(function() {
    document.documentElement.style.cssText = "--main-background-color: red";
  }, 2000);
};
html {
    --main-background-image: url(../images/starsBackground.jpg);
    --main-text-color: #4CAF50;
    --main-background-color: rgba(0,0,0,.25);
    --beta-background-color: rgba(0,0,0,.85);
}

body {
  background-color: var(--main-background-color);
}

This will only work in browsers supporting CSS variables obviously.

Upvotes: 125

Mark
Mark

Reputation: 183

For anyone who is struggling with it, if your CSS variable is a sentence you need to wrap it in qoutes.

:root {
  --my-css-var: 'Hello Person!';
}

.selector:after {
    content: var(--my-css-var);
}    

This does not work:

let myVar = 'Hi Person! (doesnt work)';
document.getElementsByTagName('html')[0].style.setProperty('--my-css-var', myVar);

But this does:

let myVar = 'Hi Person! (works)';
document.getElementsByTagName('html')[0].style.setProperty('--my-css-var', '"' + myVar + '"');

Upvotes: 9

colxi
colxi

Reputation: 8660

The native solution

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 lik this :

getComputedStyle(document.documentElement,null).getPropertyValue('--myVariable');

In my opinion, accessing CSS variables should be more simple, fast, intuitive and natural...


My personal approach

I've implemented CSSGlobalVariables a tiny (<3kb) javascript module wich automatically detects and packs into an Object, all the active CSS global variables in a document, for easier acces & manipulation.

import {CSSGlobalVariables} from './css-global-variables.js';
let cssVar = new CSSGlobalVariables();
// set the CSS global --myColor value to "green"
cssVar.myColor = "green";

Any change applied to the Object properties, is translated automatically to the CSS variables, and viceversa.

Available in : https://github.com/colxi/css-global-variables

Upvotes: 32

phil294
phil294

Reputation: 10822

If you are using :root:

:root {
    --somevar: black;
}

It will be documentElement.

document.documentElement.style.setProperty('--somevar', 'green');

Upvotes: 39

blurfus
blurfus

Reputation: 14031

You could add something like below (without using class variables)

function loadTheme() {
  var htmlTag = document.getElementById("myDiv");
  var yourSelect = document.getElementById("themeSelect");
  var selectedTheme = (yourSelect.options[yourSelect.selectedIndex].value);
  console.log("selected theme: " + selectedTheme);

  // reset class names
  htmlTag.className = '';
  // add selected theme
  htmlTag.className = 'theme' + selectedTheme;
}
.theme1 {
  color: blue;
}
.theme2 {
  color: red;
}
<div id="myDiv">
  test
</div>
<select id="themeSelect" onChange="loadTheme()">
  <option value="1">Theme 1</option>
  <option value="2">Theme 2</option>
</select>

Upvotes: 1

Oriol
Oriol

Reputation: 287960

You can simply use the standard way of setting arbitrary CSS properties: setProperty

document.body.style.setProperty('--background-color', 'blue');
body {
  --background-color: red;
  background-color: var(--background-color);
}

Upvotes: 17

johnniebenson
johnniebenson

Reputation: 540

It would probably be easier to define classes in your CSS that contain the various theme styles (.theme1 {...}, .theme2 {...}, etc) and then change the class with JS based on the selected value.

Upvotes: 0

Related Questions