How to List All CSS Variables Names/Values Pairs from Element

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>

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

Get an overview of all css variables set on root

Found the answer thanks to a post on SO. It reads the :root property from the stylesheet and loops through the properties looking for the -- keyword.

I wasn't a fan of all the filter function chaining, so I'll leave my own solution here.

/**
* Get all simpleResponse CSS variables on the root of the chat widget.
*/
function getCustomizableProperties(): string[] {

// Find the css sheet that includes the simpleResponse CSS settings.
const simpleResponseStylesheet = getSimpleResponseStyleSheet();

if (!simpleResponseStylesheet) {
console.debug('No customizable properties found. Skipping custom theme rendering.')
return [];
}

// Once found, collect the CSS settings and put them into an array.
const properties = getSimpleResponseStyleProperties(simpleResponseStylesheet);
return properties;
}

function getSimpleResponseStyleSheet(): CSSStyleSheet | undefined {
const styleSheets = Array.from(document.styleSheets);
const simpleResponseStylesheet = styleSheets.find(styleSheet => {

if (styleSheet.href === null) {
const cssRules = Array.from(styleSheet.cssRules);

return cssRules.find(rule => rule.cssText.includes('--simpleResponse'))
}
return undefined;
});

return simpleResponseStylesheet;
}

function getSimpleResponseStyleProperties(styleSheet: CSSStyleSheet): string[] {
const cssRules = Array.from(styleSheet.cssRules);

// Casting to any to access properties missing from typing.
const rootStyleRule: any = cssRules.find((cssRule) => {
const rule = cssRule as any;
return rule.selectorText === ':root';
})

const rootStyleProperties = Array.from(rootStyleRule.style) as string[];

return rootStyleProperties.filter(prop => prop.includes('--simpleResponse'));
}

This returns an array of CSS variables

0: "--simpleResponse-background-color"
1: "--simpleResponse-text-color"
2: "--simpleResponse-text-font"
3: "--simpleResponse-text-font-weight"
4: "--simpleResponse-text-font-size"

Get all CSS properties for a class or id with Javascript/JQuery

Use document#styleSheets and extract all rules from all stylesheets into array. Then filter the array by the selectorText.

Note: I've used a simple Array#includes to check if the requested selector appears in selectorText, but you might want to create a stricter check to prevent false positives. For example the selector text .demo can find rules for .demogorgon as well.

const findClassRules = (selector, stylesheet) => {  // combine all rules from all stylesheets to a single array  const allRules = stylesheet !== undefined ?     Array.from((document.styleSheets[stylesheet] || {}).cssRules || [])     :      [].concat(...Array.from(document.styleSheets).map(({ cssRules }) => Array.from(cssRules)));     // filter the rules by their selectorText  return allRules.filter(({ selectorText }) => selectorText && selectorText.includes(selector)); };
console.log(findClassRules('.demo', 0));
.demo {  color: red;}
.demo::before { content: 'cats';}


Related Topics



Leave a reply



Submit