Introducing CSS Lint
Not too long ago, Nicole Sullivan and I announced that we’ve started working together. Today, we’re happy to announce the release of our first collaboration effort: CSS Lint. The goal of CSS Lint, as you may guess, is to help you write better CSS code. We’ve spent huge chunks of time over the past couple of weeks building and debating rules to help everyone write more efficient and less problematic CSS.
The rules
To begin with, we defined several rules (explained in more detail on the CSS Lint About page). The rules are:
- Parsing errors should be fixed
- Don’t use adjoining classes
- Remove empty rules
- Use correct properties for a display
- Don’t use too many floats
- Don’t use too many web fonts
- Don’t use too may font-size declarations
- Don’t use IDs in selectors
- Don’t qualify headings
- Heading styles should only be defined once
- Be careful using width: 100%
- Zero values don’t need units
- Vendor prefixed properties should also have the standard
- CSS gradients require all browser prefixes
- Avoid selectors that look like regular expressions
- Beware of broken box models
The rules are all created using a very simple plugin model that makes it easy to change specific rules or add new ones. The ability to turn off or on specific rules isn’t yet exposed in the web or command line interfaces but is supported by the underlying API, so look for this addition soon.
In your build…
While we’re happy to introduce the web interface, we also realized that you may want to incorporate this into your build system. To help, there is CSS Lint for Node.js. You can install the CSS Lint command line tool via npm:
sudo npm install -g csslint
Once installed, you can pass in any number of files or directories with CSS files:
csslint foo.css bar.css dir_of_css/
The tool then outputs the same information as the web interface.
Contribute
CSS Lint is completely open source and available on GitHub. We’re actively looking for people to contribute rules, bug fixes, and extensions. The rules, by the way, are completely pluggable. You can easily strip out rules you don’t want or add new rules that are more specific to your needs. Then, build a custom version that suits your needs or contribute the changes back.
The CSS parser that it’s built on is also open source and available on GitHub. There are some known issues with the parser that I’m planning on addressing soon, but it’s generally CSS3-compliant.
I hope Nicole and I will be able to make more tools of this nature to help everyone write better front-end code. Enjoy!
Disclaimer: Any viewpoints and opinions expressed in this article are those of Nicholas C. Zakas and do not, in any way, reflect those of my employer, my colleagues, Wrox Publishing, O'Reilly Publishing, or anyone else. I speak only for myself, not for them.
Both comments and pings are currently closed.




31 Comments
Hey Nicholas (and Nicole)!
I think this is a really cool initiative and am happy to see the two of you starting it. My one criticism at this point is that there are no options (that I saw) to disable certain warnings. As an example, I for one, don’t think it’s horrible to use IDs in your selectors (if done correctly). Another area of concern would be for users who copy CSS resets into the mix—which will obviously be throwing a lot of duplication warnings.
Keep it up!
Kevin Sweeney on June 15th, 2011 at 2:12 pm
After your article on the sorry state of CSS3 and the mess of its syntax, it’s quite good that you create such a tool. Thank you for that!
David Bruant on June 15th, 2011 at 2:19 pm
@Kevin – The ability to turn on/off rules will be coming, we just didn’t have enough time to get it into the interfaces before our talk. The API actually already supports filtering the rules, we just need to expose it.
Nicholas C. Zakas on June 15th, 2011 at 2:47 pm
As usual taking the educator perspective. You’ve just given me a great tool! Many thanks!!!!!!!!!
Besides the possibility to pick what rules to check for, are there any other features planned for futurue updates, aka a roadmap?
One thing my students very often struggles with is whitespace. An option that requires proper indentation and use of space between property name and value would be just great.
Another common source of problems is not using semi-colon for the last rule in a block. Techniucally legal, but error prone.
Do whatever you wish with those suggestions, my main point was saying thanks!
Lars Gunther on June 15th, 2011 at 3:58 pm
Hi Nicholas (and Nicole),
A couple of things: I get parsing errors on comments like /*/*/.
Also, it warns me about margin and padding left on inline elements, even though this is perfectly valid (they do apply on inline elements).
It would be a different story if it was top/bottom margin of padding. Which makes me think that it would be very cool if the tool was also giving warning not only according to explicit declarations but also regarding type. For example, it would be great if the following would throw a warning:
span {margin: 20px 0;}
Keep up the great work!
Thierry Koblentz on June 15th, 2011 at 3:59 pm
@Lars – Thanks for your comments. Feel free to enter your wish list into the CSS Lint issues and we’ll see what we can do.
Nicholas C. Zakas on June 15th, 2011 at 4:06 pm
@Thierry – Thanks, there are definitely some parser issues we’re working through. The points you bring up are all good and I think are covered by the issues we have filed at the GitHub repo right now. If not, please feel free to add more issues. This is definitely version 1.0.
Nicholas C. Zakas on June 15th, 2011 at 4:54 pm
Have you given any thought to integrating this with a CSS compression system, like YUI or my own CSSMin [http://github.com/barryvan/CSSMin/]? In our build process, we push two CSS files to the server — a debug file, that includes whitespace etc., and a “production” file, that’s minified and tightened up.
As a side note, is it perhaps worthwhile packaging this up with something like Rhino to produce a YUI-like JAR? That way, you might get a higher rate of adoption from those who don’t want or are unable to install Node…
barryvan on June 15th, 2011 at 5:28 pm
(Sorry for another comment!)
Looking through the “About” page, it appears as though CSSLint sits halfway between standardisation and minification. For example, removing entirely empty rules should, in my opinion, occur during minification. Often, when I’m developing, I’ll fill the CSS with empty rules, and then use these as hooks for styling in Firebug.
I also wonder whether the hard-coded numbers (such as 10 floats max) should relate in some way to the size of the CSS file or the number of rules in it. Whilst these numbers make sense for websites, I’m not so sure about webapps — often, the CSS for a webapp will be two to twenty times the size of that for a website!
I think that this website-over-webapp motif is also in rules such as “Don’t qualify headings”, “Heading styles should only be defined once”. I’m looking forward to toggleable settings!
barryvan on June 15th, 2011 at 5:35 pm
@barry – I don’t see a need to bundle this with compression, two very different tools for different purposes. I am planning on making a Rhino version of CSS Lint, just ran out of time for this release. Look for it soon!
My standard answer for “I don’t like this rule” is that they will all be optional (soon). The rules we have now are the ones we find useful, and we’ll be doing more writing on why we have these rules soon. Of course, you’ll be welcome to turn off any of them that you don’t agree with.
Nicholas C. Zakas on June 15th, 2011 at 5:45 pm
Great tool. Especially eye-opening to see just how disgusting jQuery UI CSS is.
It should probably check for unique vendor prefixes like -webkit-appearance and -ms-interpolation-mode and not think that I should add the vendorless of those.
It’s also giving me a parse error if using an @page inside a media query. Here from the boilerplate print styles:
@media print {
* { background: transparent !important; color: #444 !important; text-shadow: none !important; }
a, a:visited { color: #444 !important; text-decoration: underline; }
a:after { content: ” (” attr(href) “)”; }
abbr:after { content: ” (” attr(title) “)”; }
.ir a:after { content: “”; } /* Don’t show links for images */
pre, blockquote { border: 1px solid #999; page-break-inside: avoid; }
thead { display: table-header-group; } /* css-discuss.incutio.com/wiki/Printing_Tables */
tr, img { page-break-inside: avoid; }
@page { margin: 0.5cm; }
p, h2, h3 { orphans: 3; widows: 3; }
h2, h3{ page-break-after: avoid; }
}
Erik K Veland on June 15th, 2011 at 9:16 pm
@Erik – you think you’ve found a parser error, please file an issue at http://github.com/nzakas/parser-lib
Nicholas C. Zakas on June 15th, 2011 at 9:25 pm
wait, why not use ID selectors? they’re extremely useful and i thought they were considered one of the quickest & most efficient* types of selector for css rules. i read on in the css-lint documentation that you suggest using classes, but sometimes pages have a fair amount of unique elements that require styling.
also, you may then end up with a fair amount of “one-off” classes, and then you’re still sorta tied to the HTML and—in my opinion—less semantically sound, as a class is meant for more general application.
* http://css-tricks.com/efficiently-rendering-css/
Dominick on June 15th, 2011 at 10:44 pm
@Dominick – don’t really want to get into why rules are there in the comments on this post. We’ll be expanding on the descriptions in the about section soon. Til then, I’d suggest doing a search to find the arguments, there’s plenty of info already out there.
Nicholas C. Zakas on June 15th, 2011 at 10:53 pm
[...] erst sinnvoll nutzbar, wenn ich einzelne Regeln von der Überprüfung ausschliessen kann. Zakas fasst die Regeln kurz zusammen (zur besseren Orientierung habe ich die ungeordnete in eine geordnete Liste [...]
CSSLint – ein Ansatz zum CSS-Qualitätscheck « F-LOG-GE on June 15th, 2011 at 11:24 pm
So what’s the best place to send feedback about the rules? I disagree with a couple of them, in particular not using padding or margins on inline elements.
Tim Down on June 16th, 2011 at 2:54 am
Great tool, I’ll definitely be using this.
A small detail that may add to the UI friendliness of the results table would be adding cursor: pointer to its headers. That way, it’s more obvious that those parts are clickable
Kristiaan Van den Eynde on June 16th, 2011 at 4:27 am
Not a bad tool, but I do agree that IDs have their usage and SHOULD be used when writing CSS. Also, your style.css produces 65 warnings
Matt on June 16th, 2011 at 6:03 am
I notice the parser doesn’t handle + very well. For example h2 + h6 it parses as a change to h2 not a chnage to h6.
Other than that bloody good work!
John Milmine on June 16th, 2011 at 2:25 pm
Interesting results when I ran Lint on the styles found at http://csslint.net/style.css
(Come on… you knew someone was going to try it.)
Keith Parks on June 16th, 2011 at 4:31 pm
@everyone – Few things. First, we realize not everyone will agree with all of the rules. All we can say is that in our experience working on many large-scale web sites, these rules help dramatically cut down on errors and can improve performance. We believe in these rules so we won’t be removing them. However, as I’ve said before, we will be allowing you to selectively turn on or off rules very soon (working on it now), so you can feel free to just turn off any one that you don’t agree with.
As for style.css – yes, we know. That was intentional.
There are a whole bunch of other little easter eggs on the site as well.
And please report parser errors at http://github.com/nzakas/parser-lib rather than leaving them in comments. (CSS Lint bugs may be filed at http://github.com/stubbornella/csslint)
Nicholas C. Zakas on June 16th, 2011 at 5:05 pm
Great tool. Will definitely keep this in mind for future projects.
One thing that I think should definitely be added is a warning about using
!importantMdeclarations. In general, they shouldn’t be used. There are some instances when they can be useful, but too many of them are awful for maintenance. From what I can see, the tool doesn’t seem to care about!important. Any thoughts on that?Louis on June 16th, 2011 at 9:34 pm
I don’t agree with warning about using 0 with unit if it is in compact form, and other lengths are not zero, e.g.:
padding: 4px 0px 2px 0px;Another issue is passing entered CSS in GET request… which doesn’t work for larger files (argument too long). It would be better to implement it via POST. It would be nice to allow options to point to an URL, and to upload file, like with W3C HTML Validator… though probably not all are possible beause of performance reasons.
Jakub Nar?bski on June 17th, 2011 at 2:22 am
Excellent initiative, it is likely that CSSLint enter in set of evaluation tools that all frontends must be to use. I’m watching project at github. Congratulation!
Davidson Fellipe on June 17th, 2011 at 8:00 am
[...] the original here: Introducing CSS Lint | NCZOnline Share and [...]
xhtml css templates – Introducing CSS Lint | NCZOnline | XHTML CSS - Style sheet and html programming tutorial and guides on June 18th, 2011 at 10:13 am
Looks great, works fine, but I have two questions:
- don’t understand why i can’t use IDs in selectors (for example, wordpress – and all the web designers i know – does)
- If i set the width/height along width the padding or border value, why am i mistaking? I always get the wanted goal look pixel-perfect with this method.
Great tool anyway!
jones on June 20th, 2011 at 12:20 am
How’d you come up with 10 as the limit for floats etc? It seems very arbitrary. Maybe it would be better in comparison to the length of the CSS file – a file that contains styles for a website that employs a few different variations on its layout and is a mile long might have more floats, font sizes etc than a site with just 20 rules.
Ben on June 20th, 2011 at 8:24 am
[...] CSS Lint http://www.nczonline.net/blog/2011/06/15/introducing-css-lint-2/ [...]
Getting Responsive Again on June 20th, 2011 at 10:11 am
First I must say well done for trying to make our lives easier
However just to confirm what Thierry said above you need to remove the warning for horizontal padding/margins on inline elements as they are perfectly valid and extremely useful.
In your documentation (http://csslint.net/about.html) you also state this:
“display: inline should not use width, height, margin (and all variants), padding (and all variants), or float.”
Again you mention padding and margin but it is only vertical margins that have no effect on inline elements. Vertical padding can be applied to inline elements but will have no effect on the flow of the surrounding content which means in some cases that it can be used for good effect. The warning should really only be for vertical margins on inline elements,
Finally you mention don’t use float and inline together and while that should be true the practical effect is that it will immediately cripple 99% of the sites out there in IE6 as display:inline added to float is the fix for the double margin float bug. I know IE6 is low usage these days but it’s such a simple fix.
Otherwise well done for the hard work that obviously went into this.
Paul O'Brien on June 21st, 2011 at 2:05 am
@everyone – Please file issues if there are bugs in the current rules. This isn’t the right forum for addressing them.
Nicholas C. Zakas on June 21st, 2011 at 10:25 pm
@about the ID (or hash) selector argument,
I’ve ran into a problem where I simply declared a font-color to the container,
… something like …
#content a {
color: #3333FF;
}
Then, suddenly, some links in the design (psds), required me to change their link colors, but in order to do that, I will need a higher cascade level to overwrite ‘#content a’ declaration.
… it ended like this …
#content .page-name a {
color: #FFCC33;
}
So, whenever we will change a different element (or tag) link colors, when will always be needing the ‘#content’ followed by the targeted class or element to overwrite the ‘#content a’ declaration, which in the end, became a hassle. And what actually solved the problem was to simply change ‘#content’ to ‘.content’ (now it’s class).
… So if something like this happens …
.content a {
color: #3333FF;
}
… This could easily be overwritten by …
.page-name a {
color: #FFCC33;
}
Since they are equal, except that ‘page-name a’ was declared last, so it will take effect than the previous one.
Since they said that the evaluation is based on ‘experience’, we need to somehow consider their suggestions seriously. My problem was just on a mini-site, but compare that to a larger project, that could bring more problems than mine (little project).
E-Jelome on June 24th, 2011 at 1:23 pm
Comments are automatically closed after 14 days.