By Toby Ho
Static analysis involves analyzing, rather than executing, source code, a process that is typically automated. Recently, I’ve had fun writing about static analysis for Javascript. This time, we’ll do something that’s similar but different – static analysis for CSS.
The CSS Module
The library we’ll use to help perform the static analysis is simply called css and it can be found on npm. So, assuming you already have Node.js installed, you just need to do npm install css
to install it. It contains both a parser and an emitter.
Parsing CSS
Let’s say you have a sample.css file:
.btn:hover,
.btn:focus {
color: #333333;
text-decoration: none;
}
To parse it using the css library from above, you’d write this:
var css = require('css');
var fs = require('fs');
var code = fs.readFileSync('sample.css') + '';
var ast = css.parse(code);
console.log(JSON.stringify(ast, null, ' '));
When you run this code, you’ll see its abstract syntax tree (AST) printed to the console:
{
"type": "stylesheet",
"stylesheet": {
"rules": [
{
"type": "rule",
"selectors": [
".btn:hover",
".btn:focus"
],
"declarations": [
{
"type": "declaration",
"property": "color",
"value": "#333333"
},
{
"type": "declaration",
"property": "text-decoration",
"value": "none"
}
]
}
]
}
}
Modifying the AST
Let’s say that, for whatever reason, we want all the rules in the CSS file to only take effect for elements which are descendants of certain elements – specified by the class root
. We can do that by prefixing every selector of every rule with .root
.
ast.stylesheet.rules.forEach(function(rule){
for (var i = 0; i < rule.selectors.length; i++){
rule.selectors[i] = '.root ' + rule.selectors[i];
}
});
Emitting the Modified CSS
Now that we have modified the AST, we can use the stringify()
method to regenerate the CSS from it:
console.log(css.stringify(ast))
And the output is:
.root .btn:hover,
.root .btn:focus {
color: #333333;
text-decoration: none;
}
Yay! Easy, right?
Other Possibilities
What are other interesting things you can do? You are limited only by your imagination. For example, if you want to automatically rename classes, you can do that. If you want to automatically sort or group rules by their selector, you can do that. If you want to automatically detect and remove unused rules (combined with html parsing), you can do that! You can do that!
Homework
It turns out that our example code didn’t cover all the cases. You homework is to run it against the CSS file that’s bundled with Bootstrap, figure out what’s broken, and fix it. Good luck!
This article was originally posted at http://tobyho.com/2014/01/16/static-analysis-for-css/
Brian Rinaldi is the founder of Flippin’ Awesome. Brian works as the Developer Content Manager at Telerik (though this site is not affiliated with his employer) focused on ensuring that the Developer Relations team creates top notch content for the web development community. Previously, Brian focused on publishing HTML, CSS and JavaScript developer content for the Adobe Developer Connection at Adobe.
Brian has published in a variety of technical publications over the years, has presented at numerous conferences and events and has served as a technical editor on a number of books.
You can read Brian’s blog archive with 9+ years of content at remotesynthesis.com (he still posts, infrequently). You can find a full list of Brian’s past publications and presentations. Follow Brian on Twitter @remotesynth.
Hmmm.. do projects like SASS/LESS do what you are trying to accomplish here?