Stylelint - úhledné a čisté CSS

Kvalita kódu, CSS, Tipy & triky

Čistý a uhlazený kód je velmi často vyžadován bez ohledu na programovací, skriptovací či značkovací jazyk. A CSS či jazyky preprocesorů Sass, SCSS nebo Less nejsou výjimkou. Stylelint je přesně ten nástroj, který s dodržováním kódovacích standardů pomůže.

Stylelint - úhledné a čisté CSS

Stejně jako učitelé chtěli, aby žáci psali krásně a čitelně, i programátoři chtějí, aby všichni psali kód čistě a přehledně. Každý si pod tím ale může představit něco trochu jiného. Někdo chce složené závorky na novém řádku, jiný ne. CSS pravidla seřazené abecedně nebo mít omezenou maximální délku řádku. Někdy může být i náročné na vše pamatovat, a v tu chvíli pomůže Stylelint. Nástroj, který definovaná pravidla kontroluje, upozorní na jejich nedodržení a někdy i opraví.

Stylelint + Webpack a Laravel Mix

Stylelint se chlubí, že jej používá Facebook a na Githubu najdete pravidla, která používá samotný Github (Primer) či Wordpress. Nejedná se tedy o žádné ořezávátko. Osobně jsem jej použil při tvorbě tohoto blogu. A zprovoznění je jednodušší než dodržování samotných pravidel.

.stylelintrc + .stylelintignore

Nejdůležitějším souborem je .stylelintrc, který je ve formátu YAML a obsahuje všechna pravidla. Jejich úplný seznam lze najít v dokumentaci ale výhodné je rozšířit existující soubor pravidel a také používat pluginy. Dále soubor .stylelintignore může obsahovat soubory, které při lintování ignorovat, nejčastěji stažené knihovny apod. Soubor může vypadat třeba tako

---
extends: stylelint-config-standard
plugins:
  - stylelint-order
  - stylelint-scss
rules:
  ####
  # Basic rules
  ####
  at-rule-empty-line-before:
  - always
  - except:
    - first-nested
    ignore:
    - after-comment
    ignoreAtRules:
    - else
    - import

  at-rule-no-unknown: null
  at-rule-no-vendor-prefix: true
  block-closing-brace-newline-before: always
  block-opening-brace-newline-after: always
  color-hex-case: lower
  color-hex-length: long
  color-named: never
  comment-whitespace-inside: always
  declaration-block-no-redundant-longhand-properties: true
  declaration-block-trailing-semicolon: always
  declaration-block-semicolon-newline-after: always
  declaration-block-single-line-max-declarations: 1
  declaration-colon-space-before: never
  declaration-colon-space-after: always
  function-calc-no-invalid: true
  function-url-no-scheme-relative: true
  function-url-quotes: always
  # font-family-name-quotes: always-where-required
  indentation: 4
  linebreaks: unix
  max-line-length: 120
  media-feature-range-operator-space-before: always
  media-feature-range-operator-space-after: always
  media-feature-parentheses-space-inside: never
  media-feature-name-no-vendor-prefix: true
  media-feature-colon-space-before: never
  media-feature-colon-space-after: always
  no-empty-first-line: true
  no-eol-whitespace: true
  no-descending-specificity: null
  no-duplicate-selectors: true
  number-leading-zero: always
  property-no-vendor-prefix: true

  rule-empty-line-before:
  - always-multi-line
  - except:
    - after-single-line-comment
    - first-nested
    ignore:
    - after-comment

  selector-attribute-quotes: always
  selector-attribute-operator-space-before: never
  selector-attribute-operator-space-after: never
  selector-attribute-brackets-space-inside: never
  selector-class-pattern: "^(?!js-)[a-z0-9-]+$"
  selector-list-comma-newline-after: null # Disable check
  selector-max-id: 0
  selector-no-vendor-prefix: true
  selector-combinator-space-after: always
  selector-pseudo-element-colon-notation: double
  selector-pseudo-class-parentheses-space-inside: never
  string-quotes: single
  value-keyword-case: lower
  value-no-vendor-prefix: true

  ####
  # Order plugin
  ####
  order/properties-alphabetical-order: true
  order/order:
  - custom-properties
  - dollar-variables
  - declarations
  - type: rule
    selector: '^&:[\w-]+$'
  - rules
#  - at-rules

  ####
  # Scss plugin
  ####
  scss/at-function-parentheses-space-before: never
  scss/at-function-pattern: "^[a-z0-9-]+$"
  scss/at-import-no-partial-leading-underscore: true
  scss/at-rule-no-unknown: true
  scss/dollar-variable-colon-newline-after: always-multi-line
  scss/dollar-variable-colon-space-after: always-single-line
  scss/dollar-variable-colon-space-before: never
  scss/dollar-variable-pattern: "^[a-z0-9_]+$"
  scss/declaration-nested-properties: never
  scss/function-quote-no-quoted-strings-inside: true
  scss/operator-no-newline-after: true
  scss/operator-no-newline-before: true
  scss/selector-no-redundant-nesting-selector: true
  scss/no-duplicate-dollar-variables:
    - true
    - ignoreInside: at-rule

  # SCSS plugin example config
  block-opening-brace-space-before: always
  block-closing-brace-newline-after:
  - always
  - ignoreAtRules:
    - if
    - else
  at-rule-name-space-after: always
  scss/at-else-closing-brace-newline-after: always-last-in-chain
  scss/at-else-closing-brace-space-after: always-intermediate
  scss/at-else-empty-line-before: never
  scss/at-if-closing-brace-newline-after: always-last-in-chain
  scss/at-if-closing-brace-space-after: always-intermediate

Instalace

Základ je nainstalovat Stylelint pomocí NPM. Při použití mého configu zmíněného výše je potřeba doinstalovat pluginy a výchozí pravidla a také Stylelint SCSS pokud bude použito SCSS.

npm i stylelint stylelint-config-standard stylelint-order stylelint-scss --save-dev

Kromě kontroly umí Stylelint i některé chyby sám opravit. K tomu stačí při spuštění přidat přepínač --fix. Nejjednodušší spuštění je z příkazové řádky s adresou k souborům.

# Spuštění lintu
npx stylelint resources/sass/
# Spuštění lintu s automatickou opravou
npx stylelint resources/sass/ --fix

Spouštění z Webpacku - Laravel Mixu

Přiznám se, s Webpackem neumím, proto následující ukázka obsahuje pouze konfiguraci pro Laravel Mix, který ale Webpack používá. Je tedy nutné nainstalovat webpack plugin a také registrovat do Mixu. Pokud je některé pravidlo porušeno, je zobrazena chyba i s popisem. Výsledné CSS ale je i přesto vygenerováno.

npm i stylelint-webpack-plugin --save-dev
// Tento kód přidat do webpack.mix.js
const StyleLintPlugin = require('stylelint-webpack-plugin');

mix.extend('styleLint', (config) => { config.plugins.push(new StyleLintPlugin({ files: 'resources/sass/**/*.s?(a|c)ss' })); });

mix.styleLint();

Osobní zkušenosti se Stylelintem či jinými CSS lintery můžete sdílet v komentářích

K tomuto článku již není možné přidávat další komentáře