Rob O'Leary Rob is a solution architect, fullstack developer, technical writer, and educator. He is an active participant in non-profit organizations supporting the underprivileged and promoting equality. He is travel-obsessed (one bug he cannot fix). You can find him at roboleary.net.

Level up your CSS linting using Stylelint

7 min read 2016

Using Stylelint To Improve And Lint CSS, SCSS, And Sass

Writing quality CSS is tricky. People seem to get exasperated with CSS more so than with other technologies, and that’s why I’m surprised that using a linter like Stylelint for CSS is not discussed more often. Catching and fixing errors as you go, as well as enforcing best practices while coding, can significantly improve code quality.

And, while many modern dev tools like Vue CLI and Create React App include ESLint as part of their configuration so that you can easily lint JavaScript, you are on your own when it comes to linting CSS.

This article is not meant to be a stand-in for Stylelint’s official user guide, which is well written and will cover most of your needs. This article aims to give you an up-to-date look at some of the advanced things Stylelint can do for you (which may surprise you!) and shows how you can integrate Stylelint into your workflow.

First, here’s a quick overview of Stylelint.

What is Stylelint?

If you are new to linters, you can read a tutorial on linting CSS, written by the author of Stylelint to get a complete background.

Stylelint understands the latest CSS syntax and parses CSS-like syntaxes such as SCSS, Sass, and Less.

Stylelint can extract embedded styles from:

  • HTML
  • Markdown
  • CSS-in-JS objects
  • Template literals

Essentially, Stylelint should be able to parse your CSS in any form, anywhere. Similar to ESLint, it has built-in rules to catch errors and can automatically fix some of them. It supports shareable configs and has plugins that extend the functionality. It has integrations for code editors, task runners, and some bundlers.

Using Stylelint for linting

Stylelint follows similar conventions to ESLint.

First, use npm to install Stylelint, along with the stylelint-config-standard to enable a core set of rules. Stylelint-config-standard is based on the common stylistic conventions common in a handful of CSS style guides, such as idiomatic CSS principles and Airbnb’s style guide.

We made a custom demo for .
No really. Click here to check it out.

npm install --save-dev stylelint stylelint-config-standard

Create a configuration file in the root of your project. It can be named .stylelintrc or .stylelintrc.json:

{
  "extends": "stylelint-config-standard"
}

Now you can run Stylelint on the command line. For example, to target only the CSS files in your project, run stylelint "**/*.css". To automatically fix errors, you can add the --fix flag.

Code Running Stylelint And Highlighting Two Errors

It is a good idea to read through the standard rules to gain more familiarity with Stylelint. Some people advocate starting with a blank config and only adding the rules you need, while others use the standard config as the base and modify it as they gain more experience.

The latter is certainly the fastest way to get going. I think it’s a good idea to leave auto-fix off initially so that you can see the common errors occurring and understand them. Once you’ve reached a good understanding, turn on auto-fix. Of course, it’s up to you!

Check out the official user guide if you want to learn more about Stylelint’s configuration and general usage. I will now talk about the bits I haven’t seen covered well elsewhere.

Performing lesser-known, novel tricks using Stylelint

Beyond the basics, Stylelint can do some things that you may not expect but will appreciate. If you would like an example config that uses most of what I am about to discuss, you can install my config from my npm.

Automatic ordering of properties to improve readability

The stylelint-order plugin can automatically sort properties in an order of your choosing. This can help make your CSS code easier to scan and comprehend. It is handy to have properties sorted every time you save, as below.

Code Being Automatically Organized

I would issue a word of caution with automating this on projects, as it might break stuff if it is done blindly. This is why Prettier opted not to include it as a feature. Using @mixin and @include in Sass is one area that you’d want to be careful. Because properties are included from outside the current block, changing the order of existing declarations may change the computed style for that rule.

Alphabetic ordering is not the only ordering pattern that people follow. Two additional examples are:

  1. Jonathan Snook’s SMACSS
  2. Anton Korzunov’s stylelint-semantic-groups

The idiomatic CSS style guide has some advice on which to use and when.

If declarations are to be consistently ordered, they should be in accordance with a single, simple principle.

Smaller teams may prefer to cluster related properties (e.g., positioning and box-model) together.

Larger teams may prefer the simplicity and easier maintenance that comes with alphabetical ordering.

Examples of groups are: positioning properties (position, top, bottom, left, right, float, display) and box-model properties (width, height, margin, padding).

I recommend reading the articles: “Harry Potter and the Order of CSS” by Anton Korzunov and “Organize your CSS declarations alphabetically” by Eric Bailey if you want to learn more on this topic. The authors have contrasting views!

I started to use the stylelint-config-idiomatic-order config for some of my personal projects. It organizes properties into several different groups, with the main groups being: layout, display, and box model.

The organization roughly equates to something like this:

.wrapper{ 
  /* position */
  position: absolute; 
  top: 20px;
  left: 0;

  /* display */
  display: flex; 
  justify-content: center;

  /* box-model */
  width: 100%; 
  height: 100%; 
  margin-bottom: 20px;
  margin-left: 20px; 
  margin-left: 2px;

  color: red;

  /* groups family of props together */
  border: 1px solid red;
  border-radius: 5px; 
}

If you want blank lines between the groups, you need to tweak the built-in rules related to empty lines with declaration-empty-line-before. Adding the rule below did the trick for me. It effectively disables reporting empty lines between declarations as an error.

 "declaration-empty-line-before": [
      "always",
      {
        "ignore": [
          "after-comment",
          "after-declaration",
          "first-nested",
          "inside-single-line-block"
        ]
      }
    ]

Improve accessibility

The stylelint-a11y plugin can help make accessibility a more significant part of your dev process. I think this is great. Accessibility should be a key concern and not be left until later.

The plugin adds these rules:

Recommended/Fixable Rule Rule ID Description
content-property-no-static-value Disallow unaccessible CSS generated content in pseudo-elements
font-size-is-readable Disallow font sizes less than 15px
line-height-is-vertical-rhythmed Disallow not vertical rhythmed line-height
⭐️✒️ media-prefers-reduced-motion Require certain styles if the animation or transition in media features
media-prefers-color-scheme Require implementation of certain styles for selectors with colors.
no-display-none Disallow content hiding with display: none property
no-obsolete-attribute Disallow obsolete attribute using
no-obsolete-element Disallow obsolete selectors using
no-spread-text Require width of text in a comfortable range
⭐️ no-outline-none Disallow outline clearing
no-text-align-justify Disallow content with text-align: justify
⭐️✒️ selector-pseudo-class-focus Require or disallow a pseudo-element to the selectors with :hover

⭐️: the mark of recommended rules ✒️: the mark of fixable rules.

Normalize color format

The stylelint-color-format plugin can normalize all colors to RGB(A) or HSL(A). I like to use HSL everywhere. HSL is a more intuitive format to use and has some unique applications that are not possible with other formats.

Code Adding HSL Colors

The only limitation is that if you have a color with a name, e.g., color: blue;, it won’t convert this for you.

Transition to newer recommended features such as logical properties

It’s challenging for developers to continue to learn and adapt to evolving best practices, so adding new rule sets that make new recommendations an active part of your development process is enormously helpful.

One recent example is using logical properties. Logical properties are writing mode equivalents of physical properties. They offer a way to describe the layout of web pages in a universal vocabulary that is unambiguous across different languages.

For example, you can have a single set of CSS declarations that apply to right-to-left languages (e.g., Arabic) and left-to-right languages, such as English. You can learn more about these properties in this article, CSS Logical Properties and Values.

Diagram Of Languages Showing The Direction Languages Are Read
Image credit: Web.dev

Logical properties have been around for quite some time, but it has only been in the last couple of years that adoption has significantly improved across all the major browsers. You can use the stylelint-use-logical-spec plugin to transition to logical properties and break your old habits!

Augment knowledge and catch easy-to-make mistakes

Did you know that some properties are ignored when used in conjunction with other property-value combinations?

For example, when you use display: inline, size properties such as width are ignored. This may be an obvious example to you, but others are less obvious. Obvious or not, these can be forgotten or missed in the midst of a busy project! Why don’t you let the linter catch these for you?

You can use the stylelint-declaration-block-no-ignored-properties plugin to lint these.

As a side note, some browsers have started to highlight these ignored values in their dev tools. This is how it looks in Firefox:

Firefox's Development Tool Highlighting Ignored Values

Chrome does not show this information.

Common ways to use Stylelint

I typically:

  1. Use Stylelint and Prettier to lint and format my CSS
  2. Use VS Code with the Stylelint extension to provide squiggly underlines for errors, and I set errors to be fixed automatically on save
  3. For projects that use webpack, I add the Stylelint plugin to my webpack configuration to lint styles for each build
  4. For Vue projects, I add Stylelint to my Vue CLI configuration

These are a few of the common ways Stylelint is used. I will show you how to set these situations up.

1. Using Stylelint with Prettier

Prettier is very popular for taking care of code formatting. Because Stylelint reports some formatting conventions as errors, it will clash with Prettier. Prettier will format something in a particular way, and Stylelint won’t like it.

You can include the stylelint-config-prettier in your config to disable any conflicting rules. This should always be the last referenced config in extends so that its rules are not overwritten.

{
  "extends": [
    "stylelint-config-standard",
    "stylelint-config-prettier",
  ]
};

2. Using Stylelint inside VS Code

There is a Stylelint extension you can use. Once you have installed Stylelint (globally or locally) and have added a Stylelint config to your workspace, the extension will lint open files automatically. It covers most languages that may contain CSS by default e.g., Svelte.

You probably want to add some scripts to your package.json to run it from the command line regularly.

{
     "scripts": {
       "lint": "stylelint src",
       "lint:fix": "npm run lint -- --fix",
     }
}

If you want to use Stylelint with Prettier in VS Code, I recommend installing these two extensions: Prettier and Format Code Action, which enables Prettier to be run as a code action. To format and lint CSS code when you save, you can update your user settings with the following:

{
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.formatOnSave": false,
  "editor.codeActionsOnSave": [
    "source.formatDocument",
    "source.fixAll"
  ],
}

3. Using Stylelint with webpack

If you are using webpack, you might prefer to have Stylelint run as part of the build process. You need to install the stylelint-webpack-plugin to accomplish this.

If you are using webpack through a dev tool like Create React App or Vue CLI, you need to do things differently. In the next section, I describe how to do this for Vue CLI.

To set it up in webpack yourself:

  • Install Stylelint and the webpack plugin: npm i --save-dev stylelint stylelint-webpack-plugin
  • Include the plugin in your webpack.config.js// webpack.config.js
// webpack.config.js
const StyleLintPlugin = require('stylelint-webpack-plugin');
module.exports = {
  // ... other options
  plugins: [
    new StyleLintPlugin({
      files: ['**/*.{htm,html,css,sss,less,scss,sass}'],
    })
  ]
}
  • Add your .stylelintrc config to the root directory, and you’re all set!

4. Using Stylelint with Vue CLI

For Vue CLI, you can install the npm package @steveworkman/vue-cli-plugin-stylelint to integrate Stylelint for you. To add it to an existing project, run the command vue add @steveworkman/vue-cli-plugin-stylelint and it will walk you through the setup.

npm Package Running To Integrate Stylelint

It will populate vue.config.js with your chosen plugin options and add a Stylelint config (.stylelintrc.js) for you.

It also adds the following script to your package.json:

 "lint:style": "vue-cli-service lint:style"

Conclusion

I hope that after reading this you can see how much value there is in linting CSS. Even though many frontend dev tools don’t highlight its usage or include it in their quick setup, I think using Stylelint is critical. It will save you some headaches along the way and assist you in maintaining a high level of code quality. Happy linting!

Is your frontend hogging your users' CPU?

As web frontends get increasingly complex, resource-greedy features demand more and more from the browser. If you’re interested in monitoring and tracking client-side CPU usage, memory usage, and more for all of your users in production, try LogRocket.https://logrocket.com/signup/

LogRocket is like a DVR for web apps, recording everything that happens in your web app or site. Instead of guessing why problems happen, you can aggregate and report on key frontend performance metrics, replay user sessions along with application state, log network requests, and automatically surface all errors.

Modernize how you debug web apps — .

Rob O'Leary Rob is a solution architect, fullstack developer, technical writer, and educator. He is an active participant in non-profit organizations supporting the underprivileged and promoting equality. He is travel-obsessed (one bug he cannot fix). You can find him at roboleary.net.

Testing accessibility with Storybook

One big challenge when building a component library is prioritizing accessibility. Accessibility is usually seen as one of those “nice-to-have” features, and unfortunately, we’re...
Laura Carballo
4 min read

Leave a Reply