Clean CSS with Stylelint

Last night I was working on the album functionality for this website. CSS is not my strong suit, so I wanted to get some help from a CSS linter. A CSS lint tool parses your CSS code and flags signs of inefficiency, stylistic inconsistencies, and patterns that may be erroneous.

I tried Stylelint, an open source CSS linter written in JavaScript that is maintained as an npm package. It was quick and easy to install on my local development environment:

$ npm install -g stylelint stylelint-config-standard stylelint-no-browser-hacks

The -g attribute instructs npm to install the packages globally, the stylelint-config-standard is a standard configuration file (more about that in a second), and the stylelint-no-browser-hacks is an optional Stylelint plugin.

Stylelint has over 150 rules to catch invalid CSS syntax, duplicates, etc. What is interesting about Stylelint is that it is completely unopinionated; all the rules are disabled by default. Configuring all 150+ rules would be very time-consuming. Fortunately you can use the example stylelint-config-standard configuration file as a starting point. This configuration file is maintained as a separate npm package. Instead of having to configure all 150+ rules, you can start with the stylelint-config-standard configuration file and overwrite the standard configuration with your own configuration file. In my case, I created a configuration file called stylelint.js in my Drupal directory.

"use strict"

module.exports = {
  "extends": "stylelint-config-standard",
  "plugins": [
    "stylelint-no-browser-hacks/lib"
  ],
  "rules": {
    "block-closing-brace-newline-after": "always",
    "color-no-invalid-hex": true,
    "indentation": 2,
    "property-no-unknown": true,
    "plugin/no-browser-hacks": [true, {
      "browsers": [
        "last 2 versions",
        "ie >=8"
      ]
    }],
    "max-empty-lines": 1,
    "value-keyword-case": "lower",
    "at-rule-empty-line-before": null,
    "rule-empty-line-before": null,
  },
}

As you can see, the configuration file is a JSON file. I've extended stylelint-config-standard and overwrote the indentation rule to be 2 spaces instead of tabs, for example.

To check your CSS file, you can run Stylelint from the command line:

$ stylelint --config stylelint.js --config-basedir /usr/local/lib/node_modules/ css/album.css

In my case it found a couple of problems that were easy to fix:

Stylelint album css

For fun, I googled "Stylelint Drupal" and found that Alex Pott has proposed adding a Stylelint configuration file to Drupal core. Seems useful to me!

Comments

mparker17 (not verified):

Drupal 8 core also ships with a `.csslintrc` (for https://www.npmjs.com/package/csslint ) which was added in https://www.drupal.org/node/2222049

I always forget to run linters, so I use https://github.com/icefox/git-hooks with a set of git hooks that I maintain at https://github.com/mparker17/simple-linter-git-hooks/ - the one at `pre-commit/2-css-style.sh` runs `csslint` for me when I commit (but doesn't cancel the commit), so that I can fix the issues before pushing. I'll look into adding a pre-commit hook for stylelint.

A couple of years ago I wrote two blog articles on using linters (http://openconcept.ca/blog/mparker/conforming-coding-standards-linters) and automatically running linters on commit (http://openconcept.ca/blog/mparker/automatically-running-linters-commit).

Dries:

Thanks Matt. Funny enough, I wasn't aware of Drupal core shipping with .csslintrc. I'll make sure to check out csslint!

mparker17 (not verified):

As an update to my previous comment, I added a simple linter git hook for stylelint in the `feature/stylelint-css-linter` branch to https://github.com/mparker17/simple-linter-git-hooks ; although it assumes some changes from the configuration presented in this post:

In order for stylelint to pick up its configuration automatically, I had to:

  1. Rename the configuration file from `stylelint.js` to `.stylelintrc`,
  2. Remove the `'use strict'` statement at the beginning of the file, and,
  3. Remove the `module.exports = ` assignment before the JSON settings array.

In order for stylelint to work with the configuration file, but not require the --config-basedir argument, I had to install stylelint-config-standard and stylelint-no-browser-hacks locally, i.e.: `npm install stylelint-config-standard stylelint-no-browser-hacks`.

I've put a bit more information in the commit message for d6bf406.

Add new comment

The content of this field is kept private and will not be shown publicly.

Plain text

  • No HTML tags allowed.
  • Lines and paragraphs break automatically.
  • Web page addresses and email addresses turn into links automatically.