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

Answers:

Answer

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:

var html = document.getElementsByTagName('html')[0];
html.style.cssText = "--main-background-color: red";

or

var html = document.getElementsByTagName('html')[0];
html.style.setProperty("--main-background-color", "green");

or

var html = document.getElementsByTagName('html')[0];
html.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() {
    var html = document.getElementsByTagName('html')[0];
    html.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.

Answer

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>

Answer

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.

Answer

If you are using :root:

:root {
    --somevar: black;
}

It will be documentElement.

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

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);
}

Answer

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

Answer

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 + '"');

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.