Save Expand icon

Ron Valstar
front-end developer

Change CSS styles at the root.

When building web applications a lot of times a certain elements style needs to be changed. Mostly you can suffice by using one of the Element.classList methods.
But sometimes you have to set an elements style directly (think of non-constant values like width, height, padding etc…). This is fine for single elements but when dealing with a bunch of them it feels wrong and slow having to loop through each of them.

There is a way to set or alter CSS rules at the core, albeit not a very easy one.
Lately I needed this again and refactored a script I wrote years ago. Here’s how it works.

All stylesheets rules are somewhere inside document.styleSheets, a StyleSheetList of StyleSheet objects. The StyleSheetList is an Array-like Object: meaning it does not have Array methods but it does have the length property and numerical properties so you can apply methods from the Array.prototype.

document.styleSheets {StyleSheetList}
 |-[0] {CSSStyleSheet}
 |  |-cssRules {CSSRuleList}
 |  |  |-[0] {CSSRule}
 |  |  |-[1](...)
 | [1](...)

As you know multiple CSS rules can apply to a single node. And the final value of the set property depends on the order of the rules and how specific they are.

The StyleSheet objects refers to an actual CSS file or to an inline style node. Note that it could also point to sheets set by browser extensions.

Each StyleSheet has a property called cssRules (check CSSStyleSheet interface), another array-like collection of CSSRules. The CSSRule is another interface implementation, meaning there are different types. The type we’re looking for is the CSSStyleRule which we can check by CSSRule.type or CSSRule.constructor.

The CSSStyleRule has a property selectorText, a textual representation of our CSS rule. Which finally brings us to something we can work with.
We can use a little regex to check if the rule is the one we whish to change.
IE is a bit weird here: where other browsers write a selector as nodeName#id.className1.className2 IE will do it the other way around: nodeName.className1.className2#id. So we have to do an elaborate feature check (ln 19).

Then we use CSSStyleRule.style.setProperty to alter our style.

After a bit of refactoring my script changing CSS is as easy as:

rootStyle.select('p.foo a').set({color:'green'});

Here’s the complete Gist: