Accessing a CSS Custom Property (Aka CSS Variable) Through JavaScript

Accessing a CSS custom property (aka CSS variable) through JavaScript

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

More Information here.

Access CSS variable from javascript

Just the standard way:

  1. Get the computed styles with getComputedStyle
  2. Use getPropertyValue to get the value of the desired property
getComputedStyle(element).getPropertyValue('--color-font-general');

Example:

var style = getComputedStyle(document.body)
console.log( style.getPropertyValue('--bar') ) // #336699
console.log( style.getPropertyValue('--baz') ) // calc(2px*2)
:root { --foo:#336699; --bar:var(--foo); --baz:calc(2px*2); }

Can I detect if a specific CSS custom variable exists in the loaded styles?

Many thanks to RedRex for giving me the pointer. Custom variables are accessible but not from the document.style. You have to use getComputedStyle.

So, in my web component Class, I have a connectedCallback function that runs whenever an instance of the component is added to the page.

    connectedCallback() {

// Is the correct stylesheet loaded?
if ( !getComputedStyle(this).getPropertyValue('--uib-css').includes('uib-brand') )
console.warn('[uib-theme-changer] WARNING: It appears that you are not using uibuilder\'s uib-brand.css stylesheet. This component may not work as expected.')

} // ---- end of connectedCallback ---- //

In the CSS file, I have

:root, :root.light {
color-scheme: light dark;

/* Create a checkable var - helps web components know if this stylesheet is loaded.
* NOTE: no space between : and text! */
--uib-css:uib-brand;
}

Perhaps worth noting that web components are designed to limit the interaction between the light-DOM CSS and the shadowDom CSS. However, custom variables are designed to flow into your component.

 

Footnote: For the curious, I am writing some custom web components that will play nice with Node-RED and node-red-contrib-uibuilder.

Is it possible to change CSS Variables globally via jQuery?

Since the variable is a global, you can set it anywhere in a style and the value will be updated.

$("div").click(function() {
this.setAttribute("style", "--text_color: rgb(255, 255, 255);");
});

However, I would suggest you don't modify the global variable but to update a class name instead. Have a list off root variables and use different values in different classes:

:root {
--text-color1: rgb(0, 0, 255);
--text-color2: rgb(0, 255, 255);
}
.class1 {
color: var(--text-color1);
}
.class2 {
color: var(--text-color1);
}

Now you can change the class name on click:

$("div").click(function() {
this.className = "class2";
});

How to list all css variables names/values pairs from element

Based on this answer https://stackoverflow.com/a/37958301/8620333 I have created a code that rely on getMatchedCSSRules in order to retrieve all the CSS and then extract the CSS custom properties. Since Custom properties are inherited we need to gather the one defined within the element and the one defined on any parent element.

if (typeof window.getMatchedCSSRules !== 'function') {    var ELEMENT_RE = /[\w-]+/g,            ID_RE = /#[\w-]+/g,            CLASS_RE = /\.[\w-]+/g,            ATTR_RE = /\[[^\]]+\]/g,            // :not() pseudo-class does not add to specificity, but its content does as if it was outside it            PSEUDO_CLASSES_RE = /\:(?!not)[\w-]+(\(.*\))?/g,            PSEUDO_ELEMENTS_RE = /\:\:?(after|before|first-letter|first-line|selection)/g;        // convert an array-like object to array        function toArray(list) {            return [].slice.call(list);        }
// handles extraction of `cssRules` as an `Array` from a stylesheet or something that behaves the same function getSheetRules(stylesheet) { var sheet_media = stylesheet.media && stylesheet.media.mediaText; // if this sheet is disabled skip it if ( stylesheet.disabled ) return []; // if this sheet's media is specified and doesn't match the viewport then skip it if ( sheet_media && sheet_media.length && ! window.matchMedia(sheet_media).matches ) return []; // get the style rules of this sheet return toArray(stylesheet.cssRules); }
function _find(string, re) { var matches = string.match(re); return matches ? matches.length : 0; }
// calculates the specificity of a given `selector` function calculateScore(selector) { var score = [0,0,0], parts = selector.split(' '), part, match; //TODO: clean the ':not' part since the last ELEMENT_RE will pick it up while (part = parts.shift(), typeof part == 'string') { // find all pseudo-elements match = _find(part, PSEUDO_ELEMENTS_RE); score[2] += match; // and remove them match && (part = part.replace(PSEUDO_ELEMENTS_RE, '')); // find all pseudo-classes match = _find(part, PSEUDO_CLASSES_RE); score[1] += match; // and remove them match && (part = part.replace(PSEUDO_CLASSES_RE, '')); // find all attributes match = _find(part, ATTR_RE); score[1] += match; // and remove them match && (part = part.replace(ATTR_RE, '')); // find all IDs match = _find(part, ID_RE); score[0] += match; // and remove them match && (part = part.replace(ID_RE, '')); // find all classes match = _find(part, CLASS_RE); score[1] += match; // and remove them match && (part = part.replace(CLASS_RE, '')); // find all elements score[2] += _find(part, ELEMENT_RE); } return parseInt(score.join(''), 10); }
// returns the heights possible specificity score an element can get from a give rule's selectorText function getSpecificityScore(element, selector_text) { var selectors = selector_text.split(','), selector, score, result = 0; while (selector = selectors.shift()) { if (matchesSelector(element, selector)) { score = calculateScore(selector); result = score > result ? score : result; } } return result; }
function sortBySpecificity(element, rules) { // comparing function that sorts CSSStyleRules according to specificity of their `selectorText` function compareSpecificity (a, b) { return getSpecificityScore(element, b.selectorText) - getSpecificityScore(element, a.selectorText); }
return rules.sort(compareSpecificity); }
// Find correct matchesSelector impl function matchesSelector(el, selector) { var matcher = el.matchesSelector || el.mozMatchesSelector || el.webkitMatchesSelector || el.oMatchesSelector || el.msMatchesSelector; return matcher.call(el, selector); }
//TODO: not supporting 2nd argument for selecting pseudo elements //TODO: not supporting 3rd argument for checking author style sheets only window.getMatchedCSSRules = function (element /*, pseudo, author_only*/) { var style_sheets, sheet, sheet_media, rules, rule, result = []; // get stylesheets and convert to a regular Array style_sheets = toArray(window.document.styleSheets);
// assuming the browser hands us stylesheets in order of appearance // we iterate them from the beginning to follow proper cascade order while (sheet = style_sheets.shift()) { // get the style rules of this sheet rules = getSheetRules(sheet); // loop the rules in order of appearance while (rule = rules.shift()) { // if this is an @import rule if (rule.styleSheet) { // insert the imported stylesheet's rules at the beginning of this stylesheet's rules rules = getSheetRules(rule.styleSheet).concat(rules); // and skip this rule continue; } // if there's no stylesheet attribute BUT there IS a media attribute it's a media rule else if (rule.media) { // insert the contained rules of this media rule to the beginning of this stylesheet's rules rules = getSheetRules(rule).concat(rules); // and skip it continue }
// check if this element matches this rule's selector if (matchesSelector(element, rule.selectorText)) { // push the rule to the results set result.push(rule); } } } // sort according to specificity return sortBySpecificity(element, result); };}
var element = document.querySelector(".box");
/*Get element style*/var obj = window.getMatchedCSSRules(element)[0];var all_css = obj.parentStyleSheet.cssRules;for(var i=0;i < all_css.length;i++) { var rules = all_css[i].cssText.substring(all_css[i].cssText.indexOf("{")+1,all_css[i].cssText.indexOf("}")); rules = rules.split(";"); for(var j=0;j<rules.length;j++) { if(rules[j].trim().startsWith("--")) { console.log(rules[j]); } }}/*get inline style*/var rules = element.getAttribute("style").trim().split(";");for(var j=0;j<rules.length;j++) { if(rules[j].trim().startsWith("--")) { console.log(rules[j]); }}
:root {  --b: 20px;}
.box { background: red; height: 100px; --c: blue; border: 1px solid var(--c);}.element { --e:30px; padding:var(--e);}
<div class="box element" style="color:blue;--d:10ch;border-radius:20px;"></div>

How to generate CSS variable values to a new stylesheet

You can download the file as text then find and replace the variables.

For example:

var s = `pre[class*="language-"] {  background: var(--block-background);}`
const variables = {"block-background":"#0D2831"};
Object.keys(variables).forEach(key => { s = s.replace("var(--"+key+")", variables[key]); });
console.log(s);

Get element's custom css properties (-mystyle) using JavaScript

CSS values not understood by the browser are discarded, which explains why -my-custom-property was unavailable via .style.

In the past, you would have had to rely on storing the data with data attributes and dealing with inheritance yourself via JavaScript.

However, "custom properties", aka "CSS variables", have since been introduced into the standard and implemented by browsers, with ~92% support globally as of 2019-05-09. At a quick glance, Edge seems to have been the last major browser to implement, with version 16 on October 16, 2017.

Essentially, you need to set a custom property (eg, --my-custom-property: 'foobar';) on an element, and it can be accessed with something like getComputedStyle(your_el).getPropertyValue("--my-custom-property") which would return 'foobar' (with a leading space). Note the leading space and quotation marks. It will return the value exactly as it was provided.

Example:

console.log(getComputedStyle(document.getElementById("a")).getPropertyValue("--my-custom-property-1"))console.log(getComputedStyle(document.getElementById("b")).getPropertyValue("--my-custom-property-2"))
#b-div { --my-custom-property-2: 'world' }
<div style="--my-custom-property-1: 'hello'"><h1 id="a">#a 'hello'</h1></div><div id="b-div"><h1 id="b">#b 'world'</h1></div>

Accessing css variable in JS file

Assuming you're using native CSS variables and not some preprocessor, take a look at this page. At the bottom there's a section called Values in JavaScript which describes how to access native CSS vars in JS code.

getComputedStyle(element).getPropertyValue("--my-var");

However if you are using a CSS preprocessor, it is not possible to retrieve the variables via JS since they're already processed in the build process.



Related Topics



Leave a reply



Submit