HTML & CSS - - By Ashley Nolan

Taking CSS Linting to the Next Level with Stylelint

As front-end development has matured, the use of tools addressing code quality has grown substantially.

This is perhaps most evident when looking at the JavaScript ecosystem. Using a JavaScript linter is now the expected standard for front-end developers to ensure that their code is well structured and consistent. In fact, in my recent tooling survey, the vast majority of developers stated that they lint their JavaScript.

When it comes to writing CSS, the drive towards using code quality tools has been a little slower, with the majority of developers in that same survey stating that they chose not to use a CSS linter in their workflow.

Stylelint Demo

I want to address this shortfall today, looking at one tool in particular that has raised the bar when it comes to linting stylesheets: stylelint.

It’s worth noting up front that although I reference CSS throughout this article, these references are interchangeable with a preprocessing language such as Sass. Stylelint can evaluate Sass and Less files as well as plain CSS and we’ll look at this in more detail later in the article.

A (Very) Brief History of CSS Linting

When CSS linting was first introduced as a concept, it was fairly polarizing. Shortly after CSS Lint was introduced back in 2011, I remember reading an article by Matt Wilcox called CSS Lint is harmful, which criticized the opinionated nature of some of its rules – a sentiment that was shared by many in the community.

Looking back, CSS Lint was much like the first JavaScript linting tools that were available, such as JSLint – opinionated and not very flexible. However, while tools such as JSHint and ESLint emerged and pushed JavaScript linting forward, alternatives in the CSS linting landscape were non-existent.

That is until stylelint arrived on the scene.

Why Stylelint?

There are a few reasons why I think stylelint is now the best tool available when it comes to linting your CSS.

Firstly, it is completely un-opinionated. That means you can enable as few or as many rules as you like, with a number of its rules giving you options to configure them to your preferences.

Also, it has a huge array of rules available – over 150 in fact, not including language specific rules for preprocessor specific syntax. Spending a little time to look through these is invaluable to building up a set of rules that fits how you write your styles.

It is also very flexible, understanding CSS and CSS-like syntax such as SCSS and Less. So whether you want to lint preprocessor code or vanilla CSS, stylelint has you covered.

Lastly, and perhaps most importantly, its documentation is excellent. Want to see what rules are available? Check out the detailed documentation covering all available rules. How about some advice on how to contribute a new rule that you might like? They have a great developer guide to help you with that too.

What Can Stylelint Do?

The value of adding a linting step when developing in any language is to improve the consistency of the code that you’re writing and to reduce the number of errors in your code.

When applying this to CSS there are a number of issues that stylelint can help you address.

Syntax Errors

Syntax errors are not subjective errors and should be very clear once highlighted.

Consider the following example:

.element {
  color: #EA12AE1;
  disply: block;
}

The above code shows two different syntax errors. The first error is an invalid hex color. The second is a typo when declaring the display property.

These are pretty basic syntax errors that can get picked up by stylelint using rules such as color-no-invalid-hex and property-no-unknown, saving you the headache of having to find the mistake manually.

Formatting and Consistency

In CSS, code style preference can be extremely subjective. Chances are the way that I like to write my CSS isn’t the way that you prefer to write yours. It’s therefore important that a CSS linter can adapt to your preferences rather than trying to force a set of rules on you.

Consider the following styles:

.listing {
  display: block;
}

.listing-item
{
  color:blue;
}

.listing-img{
  width : 100%}

.listing-text { font-size: block; }

.listing-icon {
  background-size: 0,
    0; }

All of the rule sets above contain valid CSS, but they are clearly not consistent with one another in style. Use of spacing in each declaration is different and each block is formatted in a slightly different way.

This example shows just a few possible ways of formatting CSS. But in reality there are hundreds of subtle variations. Over a whole stylesheet (or multiple files), inconsistencies such as these can hinder the readability and maintainability of your code.

This inconsistency becomes more apparent when a project is worked on by multiple developers, as each one might prefer to write their styles in a slightly different way. It’s always beneficial to get together and agree on a set of formatting rules that you will all stick to in such a situation.

Stylelint allows you to customize a set of rules to match the way that you, or your team, prefer to format your styles. Whatever preferences you have, stylelint can check that these rules are being applied consistently across your project.

Reduce Duplication in Styles

Duplication can be a pain to debug, whether it’s the duplication of selectors or properties in a stylesheet.

Take a look at the following CSS:

/* Property duplication */
a {
  display: block;
  color: orange;
  font-size: 1.2rem;
  display: inline; /* duplicate */
}

/* Selector duplication (1)
   Same selector, at different points in stylesheet */
.foo {}
.bar {}
.foo {}

/* Selector duplication (2)
   The same group of selectors, simply ordered differently */
.foo, .bar {}
.bar, .foo {}

Stylelint has several rules that can help spot this kind of duplication in your code, such as the declaration-block-no-duplicate-properties rule that will catch duplicate properties.

It can also be configured to ignore intentional duplication, such as when the same property has been defined to provide a fallback value:

.example {
  font-size: 14px;
  font-size: 1.2rem; /* will override the above if browser supports rem */
}

Best Practice Checks

Best practices in CSS are somewhat subjective, but stylelint give you total flexibility in how you want to check for these “errors”, if at all.

One commonly accepted best practice that falls into this category would be to throw an error when a certain selector nesting depth is exceeded when writing preprocessor code. This is useful to ensure that the specificity level of your styles is kept to a reasonable level and doesn’t get out of hand.

Different developers and different use cases mean that what is deemed to be ‘acceptable’ may change from project to project. For example, you may have a legacy stylesheet in which you want to ensure the nesting depth doesn’t get any worse. The max-nesting-depth rule lets you define your own acceptable nesting depth to check against, meaning that this rule could be useful for any project that uses a preprocessor.

Limit Language Features

The final set of checks that stylelint gives you access to is what they call ‘Limit language features’ in their rule guide. These can be used to enforce your own feature rules when working with your stylesheets.

A common example would be if you use a tool like Autoprefixer to automate adding vendor prefixes to your styles. In this scenario, it would be useful to throw a warning or an error if a vendor prefix has been manually added by a developer, as this will help to keep your code clean of unnecessary prefixes that will get added when the tool is subsequently run over unprefixed styles. Stylelint can take care of this for you with its ‘value-no-vendor-prefix’ rule rule, which does exactly that.

Other examples of rules range from disallowing named colors or specifying the maximum precision of numbers, to being able to blacklist certain properties if you so wish to.

These rules are more opinionated by their very nature, but you can use them however you choose to. This means that your projects’ linting rules are tailored to how you and your team like to write your styles.

Using Stylelint

We’ve covered what stylelint can do, but how easy is it to set up and use?

Like its rule set, stylelint is extremely flexible. There are a number of plugins available that make it easy to integrate into whichever build tool you prefer to use, as well as editor plugins for Atom, Sublime Text, and Visual Studio Code.

In terms of setting up your own rule set, there are multiple ways to do so. The easiest way is to create a .stylelintrc file in your project’s root directory inside which you can start to build your own rules such as:

{
  "rules": {
    'block-closing-brace-newline-before': 'always-multi-line',
    'block-closing-brace-space-before': 'always-single-line',
    'color-no-invalid-hex': true,
    'comment-no-empty': true,
    'unit-case': 'lower',
    'unit-no-unknown': true,
    // etc...
  }
}

When you then run your stylelint task – for example as part of your Gulp or webpack build – it will pick up the above configuration and use those rules to lint your styles.

Similar to JavaScript linting tools like ESLint, you can also use an existing configuration as a starting point and add your own rules. Stylelint has a recommended base configuration that you can extend, or you can choose to extend from more opinionated rule sets based on methodologies such as SUIT CSS.

My advice would be to spend a little time looking through the available rules and creating a configuration that you and your team are happy with. Once proven useful, you could take the extra step of having your configuration available as an installable npm module – like the extendable rule sets mentioned above – so that you can then install and keep your stylelint configuration in sync across all of your projects.

Linting Preprocessor Code

As I mentioned earlier, stylelint can lint Sass or Less as easily as it can CSS.

Setting this up depends on how you use stylelint. If you’re using a plugin for a build tool such as Gulp or webpack, you can pass through a value for stylelint’s syntax option. This option takes less or scss as values depending on which syntax you wish to lint.

As an example, to specify that you would like to lint your .scss files, you would pass the following object in as your stylelint options:

{
  syntax: 'scss'
}

If you want to find out more on how you can use stylelint to lint preprocessor code, there’s a great section in its documentation dedicated to explaining just that.

Go Forth and Lint!

As you can see, stylelint has brought CSS linting a long way in a relatively short time. Its flexibility and breadth of rules means that you can set up a configuration that is as detailed or as hands off as you like, helping you to keep your styles more consistent, maintainable, and error free.

It’s my hope that more developers choose to make use of such an excellent tool; so try taking it for a spin. Your stylesheets will thank you for it.

Sponsors
Login or Create Account to Comment
Login Create Account