ここ最近の CSS を取り巻く状況の変化は目覚ましいものがあり、これまでにはない速度でブラウザのサポートも進んでいます。その反面、使用できるプロパティが大幅に増えたことで、CSS プロパティ(宣言)の記述順の一貫性を保つことが難しくなりました。

そのような状況を踏まえ、この記事では、CSS を書くときのプロパティ(宣言)の記述順の再考と、Stylelint を導入して自動的に修正を適用する方法を検討していきます。

紹介する CSS プロパティの記述順はあくまでも個人の主観にとどまります。

膨大な CSS プロパティを 1 つずつ検討して並べていくのは現実的ではないので、まずはいくつかのグループに分けます。

いくつかの分類方法が考えられますが、CSS の仕様はモジュールごとに開発が進んでいるので、このモジュール単位で分類すれば、プロパティが増えたときにも対応しやすく合理的だと感じました。

そこで、W3C が提供する、CSS の仕様の進捗状況をまとめた CSS Snapshot 2023 の References に掲載されているモジュールをベースに考えていきます。

ここに必要なプロパティを追加した計 492 のプロパティを、仕様の各モジュールごとに以下の 43 のグループごとに並べていきます。

  1. Cascading and Inheritance
    all
  2. Generated Content
    contentquotes
  3. Positioned Layout
    positioninset など
  4. Containment Module
    conatinercontain など
  5. Display
    displayordervisibility
  6. Grid Layout
    gridgrid-comumn など
  7. Flexible Box
    flexflex-flow など
  8. Box Alignment Module
    gapalign-contentjusitify-content など
  9. Float
    floatclear
  10. Multi-column Layout
    conatinercontain など
  11. Overflow
    overlfowtext-overflow など
  12. Overscroll Behavior
    overscroll-behavior など
  13. Masking
    clipmask など
  14. Box Sizing
    box-sizinginline-sizeblock-size など
  15. Box Model
    marginpadding など
  16. Backgrounds and Borders (border)
    borderborder-radius など
  17. Shapes
    shape-outside など
  18. Images
    object-fitimage-rendering など
  19. Lists and Counters
    list-stylecounter-reset など
  20. Tables
    table-layoutborder-collapse など
  21. Color Adjustment
    color-scheme など
  22. Backgrounds and Borders (background)
    backgroundbackground-color など
  23. Color
    coloropacity など
  24. Compositing and Blending
    mix-blend-modebackground-blend-mode など
  25. Fragmentation
    box-decoration-break など
  26. Writing Modes
    writing-modedirection など
  27. Fonts
    font-familyfont-size など
  28. Inline Layouts
    line-heightvertical-align など
  29. Text Module
    text-alignwhite-space など
  30. Text Decoration
    text-decorationtext-shadow など
  31. Ruby Annotation Layout
    ruby-position など
  32. Filter Effects
    filter など
  33. SVG's Presentation
    fillstroke など
  34. Scroll Snap
    scroll-snap-typescroll-snap-align など
  35. Scrollbars Styling
    scrollbar-colorscrollbar-width
  36. Basic User Interface
    outlineresizepointer-events など
  37. Motion Path
    offset-path など
  38. Transforms
    transformtranslate など
  39. Will Change
    will-change
  40. Transitions
    transition など
  41. Animations
    animation など
  42. Scroll-driven Animations
    animation-rangescroll-timeline など
  43. View Transitions Module
    view-transition-name

グループの順番はスタイルを適用したときの影響範囲の外側から内側へとなるように並べていますが、そこまで厳密ではなく、いくつか例外もあります。

例えば、影響範囲が全体に及ぶ可能性のある Writing Modes を関連性の強い Fonts の直前に配置していたり、UI や変形、アニメーションに関連するプロパティは最後に配置したりと、個人的な使い勝手を考慮したアレンジを加えています。

プロパティの順番が決まったので、スタイルに反映していきますが、当然ながらこの順番を正確に記憶するのは不可能ですし、すでに存在する CSS の記述順を手作業で変更するのも論外です。

そこで、CSS の Linter(静的解析ツール)である Stylelint と、そのプラグインである stylelint-order を使用します。

まずは、Stylelint と stylelint-order をインストールします。

Stylelint と stylelint-order をインストールするコマンド
npm install --save-dev stylelint stylelint-order

本サイトのフレームワークは Astro を使用しており、.astro ファイル内の <style> にも反映する必要があるため、postcss-html と stylelint-config-html をインストールします。

postcss-html と stylelint-config-html をインストールするコマンド
npm install --save-dev postcss-html stylelint-config-html

続いて、Stylelint の設定ファイル .stylelintrc.yml をルートディレクトリに作成します。この設定ファイルは JSON 形式や JS 形式にも対応していますが、コメントが使えて簡潔に記述できるため YAML 形式を選択しました。

.stylelintrc.yml
extends: stylelint-config-html/astro

plugins:
  - stylelint-order

rules:
  order/properties-order:
    -
      # Cascading and Inheritance
      - all

      # Generated Content
      - content
      - quotes

      # Positioned Layout
      - position
      - top
      - right
      - bottom
      - left

      # ...

まず、extends.astro ファイルにも対応するようにし、plugins には stylelint-order を指定し、rules でプロパティの並び順を指定しています。

前述した 43 のグループの並び順以外でのルールとしては以下のとおりです。

  • ショートハンドプロパティを優先
  • -webkit- などのベンダープレフィックスは除く(stylelint-order 上で補完してくれるため)
  • モジュールには含まれないが関連性が強いものは含めてもよい(例:z-index を Positioned Layout に追加)
  • SVG のプレゼンテーション属性(fillstroke)については、必要最小限なプロパティのみを抜粋
  • 使用する可能性が極めて低いプロパティは、処理の負担を抑えるためにコメントアウトで無効化

コードの全体は、以下の GitHub Gist から確認できます。

ちなみに、この rulesorder/properties-order では、groupName を付与してプロパティのグループを明示的に階層化することもできますが、コメントでも十分なのと、ループ処理の負担を低くするために使用は見送りました。

また、unspecified オプションでは含まれていないプロパティの処理を指定できますが、デフォルトから変更していないので単純に並び順のチェックから無視されます。

すべてのオプションについては、stylelint-order の GitHub リポジトリを参照してください。


これで、Stylelint が実行できるようになったので、npm-scripts に追加します。

package.json
{
  // ...
  "scripts": {
    "lint": "stylelint \"src/**/*.{css,astro}\"",
    "lint:fix": "stylelint --fix \"src/**/*.{css,astro}\""
  },
  // ...
}

ここでは、解析のみを実行する lint と、解析結果のエラーを修正する lint:fix の 2 つのスクリプトを追加しました。試しに npm run lint を実行すると、以下のように解析結果がコンソールに表示されるようになります。

ターミナルで Stylelint を実行したときのスクリーンショット
対象のファイルが解析されてレポート結果が表示される

CLI の詳細については、Stylelint の公式ドキュメントを参照してください。

ここまでの設定で、CSS のプロパティの記述順を統一することができました。次のセクションでは、Stylelint を自動的に適用する方法を紹介します。

CSS プロパティ(宣言)の記述順のルールを徹底するために、Git フックを使用して、コミットするタイミングで Stylelint の解析と修正を適用するようにします。

Git フックマネージャとしては、husky が有名ですが、ここでは軽量で使い勝手の良さそうな Lefthook を選択しました。

まずは、Lefthook をインストールします。

Lefthook をインストールするコマンド
npm install --save-dev lefthook

次に、Lefthook の設定ファイル lefthook.yml をルートディレクトリに用意します。

lefthook.yml
pre-commit:
  commands:
    stylelint:
      root: 'src/'
      glob: '**/*.{css,astro}'
      run: npx stylelint --fix {staged_files}
      stage_fixed: true

ここでは、コミットのタイミングで npx stylelint --fix コマンドが、src/**/*.{css,astro} に一致するファイルで、なおかつステージングされたファイルに対して実行するように指示しています。

最後の行の stage_fixed: true によって、コマンドでステージングされたファイルが修正されたときに、その変更をコミットに含めることができます。

設定ファイルを用意したら、Git フックを設定するためのコマンドを実行します。

Git フックを設定するコマンド
npx lefthook install

この状態で Git にコミットすると、設定した Stylelint が実行されます。

ターミナルで Git にコミットしたときのスクリーンショット
Git にコミットすると Lefthook に設定したスクリプトが実行される

Stylelint を Git フックに設定すべきか

見出し「Stylelint を Git フックに設定すべきか」

ここまでで、Lefthook 経由で Git フックが設定され、コミットするたびに Stylelint が実行されるようになり、CSS プロパティ(宣言)の記述順の一貫性を保つことができるようになりました。

宣言ブロックの順番とは異なり、プロパティ(宣言)の順番が変わることでのスタイルへの影響のリスクは、同一のプロパティや、競合するプロパティ(margin-topmargin-block-start など)が含まれていない限り考えられません。

しかし、最近ではネスト記法や多くの at-rules が登場し、CSS の書き方が変わってきており、プロパティ(宣言)の順番を変更することによるスタイルへの影響が発生しないとも言い切れません。自動化した場合にはこの影響に気づかずにデプロイしてしまう可能性があります。

また、コミットするたびにスクリプトが実行されるので、わずかながら待ち時間が追加されてしまうのも少しだけ気になる点です。

このような懸念は残りますが、ひとまず Git フックによる自動化は有効にしたまま様子見とし、問題があるようであれば手法を見直したいと考えています。

この記事では、CSS の仕様のモジュールごとに CSS プロパティを分類する方法で記述順のルールを作成しました。Stylelint を使うことで、この CSS プロパティの記述順のルールの解析と修正を委ねることができました。

さらに、Git フックマネージャ(Lefthook)を導入することでコミット時に自動的に Stylelint が実行されることで一貫性を持たせることができました。

今回作成したルールについては、実際に運用しながら気になった点があれば調整していきます。