Skip to main content
Home / Articles /

Lint your CSS with stylelint

You write CSS. Probably a lot of CSS. And you make mistakes. Probably a lot of mistakes. Somebody needs to stop you from making mistakes in your CSS.

Sometimes your mistake is a real bug. Sometimes it’s just sloppy, inconsistent, or unclear coding style. Some of them may seem trivial at first (depending on your temperament), but they become patently important as the codebase grows and ages, as more people stick their hands in it and do ugly things. Things you thought unimaginable.

You try to control yourself. Your colleagues pitch in, too, correcting you when you stray. But both you and your colleagues are mistake-makers, so will naturally, inevitably fail, at least in part. And later on you or some other sorry sap will face the consequences of those mistakes that slipped into your CSS.

Neither you nor your colleagues like talking about the mistakes you’ve made. It’s awkward. Sometimes it’s discouraging and divisive. Certain conventions that definitely help the codebase, like consistent formatting, may seem pedantic and tedious when enforced manually. Or else they bring out the pushy and pigheaded elements in people you usually like.

Additionally, you’d much rather be corrected right away than wait for a code review just so someone can point out that you duplicated a declaration and should clean up your spacing. Instant feedback would help you internalize conventions and spend a little less time floundering when your CSS doesn’t work.

What you really need is a mistake-preventing machine

You need a dependable mistake-preventing machine that understands CSS and understands you: your intentions, preferences, ideals, and weaknesses.

Such a machine would have its limitations. All things do. But its limitations would differ from those of you and your human colleagues. Whatever mistakes it can prevent it will prevent consistently, tirelessly. Meanwhile, you and your colleagues can work on improving the machine, expanding its powers and diminishing its limitations. If it is open-sourced, other contributors from around the world can join the effort — other fallible CSS authors equally invested in preventing their own mistakes.

CSS authors need linters just like everyone else

We call these mistake-preventing programs “linters.” JavaScript has several good ones. ESLint, in particular, has been working wonders, showing us all just how helpful a good linter can be. But in the realm of CSS we have not been so fortunate. We’ve had very limited options: the Ruby-based, preprocessor-specific scss-lint and the older CSS Lint.

But that was before the advent of PostCSS. Among other things, PostCSS provides the means to build more interoperable CSS tools. It can parse any CSS*-like* syntax into an Abstract Syntax Tree (AST) for plugins to analyze and manipulate. And with custom parsers, PostCSS can handle even non-standard, technically “invalid” patterns (like //-comments).

The conditions are ripe for a mighty new stylesheet linter — powered by PostCSS and inspired by the best features of scss-lint and ESLint.

I’ve been working with a few collaborators on this project, and I’m writing now to introduce you to the tool we’ve developed: stylelint.

Some things you can do with stylelint

What follows is an attempt to summarize stylelint’s features, which include over a hundred rules and thorough extensibility.

If at any point you find yourself growing impatient (“OK, OK: I’m convinced that stylelint works wonders. No more summary necessary.”) just skip to the next section, where I’ll anticipate some questions and offer some tips.

#1) Catch errors

Some stylelint rules aim to catch obvious errors, usually typos or oversights made when you were rushed, distracted, or bleary-eyed. For example, you can disallow empty blocks, invalid hex values, duplicate selectors, unknown animation names, and mistaken linear-gradient syntax.

Other rules do their best to catch more subtle errors.
There’s a rule that warns when you’ve used a shorthand property (like margin) that will override one of its longhand counterparts (like margin-top), which you’ve probably done inadvertently. And there’s a rule to warn you about the confusing situation when Rule A comes before Rule B but in fact overrides Rule B, because Rule A’s selector has a higher specificity (e.g. Rule A is {...} and Rule B is .foo {...}). That’s a tricky one.

Another rule uses the PostCSS plugin doiuse to check whether your styles will work for the browsers that you intend to support. And yet another uses css-colorguard to complain about colors so similar that you probably intended them to be identical. (Notice that? It’s one of the major advantages of stylelint being built on top of PostCSS: with very little effort, stylelint can introduce rules that use other analytical PostCSS plugins.)

#2) Enforce best practices

If you use a systematic methodology in your stylesheets or have a styleguide for your code, you should be able to decisively outlaw certain patterns. stylelint provides the means to do so.

Above all, you need to control your selectors. Ruthlessly. With stylelint, you can disallow selectors that exceed a certain specificity, or put a cap on nesting depth. You can forbid categories of selectors (e.g. no id selectors) and provide regular expressions to enforce naming conventions for the rest.

You can block the use of !important, or browser hacks that don’t apply to browsers you support. If you use Autoprefixer (which you probably should), you can disallow the use of vendor prefixes in your source stylesheets.

If you want to get really serious — investing some extra time in configuration to ensure absolute consistency — you can enforce the order of properties in your rules, and provide blacklists and whitelists for properties, values, functions, and units.

#3) Enforce code style conventions

stylelint has a host of rules that automatically enforce code style conventions, so you and your teammates don’t have to. We’ve tried to make these rules extremely comprehensive and extremely flexible.

These rules are mostly about whitespace, but also target other details like quotation marks, letter case, leading zeros on fractional numbers, the use of keywords vs. spelling out values, and so on.

The dream is that you and your teammates can establish a formatting convention once (e.g. “Let’s always have a single space after a declaration’s colon!”), codify that into stylelint’s configuration, and then never talk about it again. Leave enforcement to the machine empire.

#4) Customize and extend everything

Nicholas Zakas, the creator of ESLint (and also CSS Lint), has written that the key to ESLint’s success is its extensibility. stylelint tries to follow ESLint’s lead and provide CSS authors with a linter that is as extensible as possible.

You can write and publish your own rules as plugins. There are a bunch available already; and we’re eager to see what else people come up with.

Configurations are extendable and therefore shareable. As with plugins, we learned the value of this feature from ESLint. Check out what’s published already, which includes configs from WordPress and SUITCSS.

If you don’t like stylelint’s built-in reporters you can craft your own, even tailor one to your organization. You can also customize the warning messages that rules deliver.

Using stylelint’s API, you can create plugins for text editors and task runners that integrate stylelint into every aspect of your workflow.

And if you can think of any other ways that you’d like to extend stylelint, let us know!

Answers to anticipated questions

There are probably a few questions swimming around in the murky waters of your mind. Here are answers to the most common ones we’re asked:

Can I use stylelint with SCSS? Or Less?

Yes, you can use stylelint with SCSS! And Less support just arrived! Since PostCSS allows custom parsers, stylelint has no trouble supporting various non-standard syntaxes — anything that you can write a PostCSS parser for.

Right now there are PostCSS parsers — and therefore stylelint support — for SCSS, Less, and the new SugarSS. If you want another custom syntax supported now, help out by working on the PostCSS parser!

Of course, certain rules might stumble on certain aspects of your non-standard syntax (e.g. confuse Sass #{$interpolation} for id selectors). Because stylelint tries to cover the fractured landscape of our stylesheets — where some people use standard CSS, some an extension language like SCSS, some weird custom properties, etc. — there will always be holes to fill. But we’ve been addressing these bugs as we find them; and in the meantime any rule can be turned off completely or disabled on a stylesheet-by-stylesheet or line-by-line basis.

Can I use stylelint with future CSS syntax?

Yes! Same answer as above, really: stylelint can understand everything that PostCSS understands, which definitely includes whatever future CSS syntax you are enabling (probably via PostCSS plugins). In fact, some of stylelint’s rules specifically target future CSS like range features and custom properties.

A stylelint configuration can be huge. Where should I start?

We recommend building your configuration in one of three ways:

  • Extend a published configuration. We maintain stylelint-config-standard to provide a solid baseline for most users. And plenty of other configurations have already been published.
  • Start from scratch and add one rule at a time. No rules are turned on by default, so by adding each rule yourself you will know exactly what is being enforced, and will gain an understanding of each rule as you add and configure it.
  • Copy-paste this starter configuration and decide which options to use and which rules to delete.

Thankfully, you should not have to write huge stylelint configurations over and over again. Create one tailored to your tastes and use it everywhere you can.

What’s the easiest way to run stylelint?

The simplest, best way for most people to run stylelint is through its CLI.

If you’d prefer a gulp plugin, give gulp-stylelint a shot. For webpack, there are a couple of possibilities. We hope these plugins will inspire people to develop stylelint plugins for other task runners, like Grunt. (Easy open source opportunity if you’re looking for one!)

You can also run stylelint as a PostCSS plugin, including it in any PostCSS runner’s chain of plugins. This means that you can use stylelint anywhere you can use PostCSS — which covers pretty much every compilation tool out there!

Also, there are already stylelint text editor plugins for Atom, Sublime Text, and VS Code — providing the fastest possible feedback as you work. For those and more, check out the Complementary Tools list on stylelint’s website.

Here’s what you can expect to see in the command line:

Example of stylelint output on the command line.

And here’s what it looks like in Atom:

Example of stylelint output in Atom.

Will stylelint fix my mistakes?

No, but another project called stylefmt aims to do just that. It takes a stylelint configuration — the very same one that you use for linting — and fixes whatever mistakes it can. We’re hoping that, with community contributions, stylefmt will grow until it can auto-fix as many stylelint rule violations as can possibly be auto-fixed. Help them out!

Update: stylelint does have a --fix flag now for auto fixing issues.

You could also use other tools like CSScomb or perfectionist in tandem with stylelint, auto-fixing what you can and auto-enforcing the rest.

Supplement discipline with linting

There’s an extraordinary amount of discipline in good CSS. That’s why we spend so much time talking about methodologies like SMACSS, ACSS, BEM, SUITCSS, ITCSS, and so on. We all know that it’s very easy to write CSS very badly, so in our own work we need to establish an intelligent strategy and doggedly stick to it if we’re going to write stylesheets that won’t make us cringe next week.

stylelint’s ambitious goal is to supplement our discipline with automatic enforcement — to provide a core set of rules and a pluggable framework that CSS authors can use to enforce their own strategies.

Give it a try and let us know how to works for you. And if you have ideas for improvement, pitch in! Contribute rules, enhancements, tests, bug fixes, documentation, new ideas, or just feedback. There’s work to be done for developers of all levels.