CSSモジュールはこう書きたい
React.jsとCSSモジュール(CSS Modules)を採用するとき、こういう指針でコーディングできたらという所感です。
CSSよりSass
CSS1本で抽象化できるメンバーが揃うと言い切れる場合を除き、基本的にはスタイル抽象化のためにSass(scss)を導入するのが無難です。
理想とは違い、現実的に全てのスタイル定義がコンポーネントの区切りに適合する訳ではないと感じます。例えばcreate-react-app公式に書いてあるような「コンポーネントがあればプリプロセッサは不要(要約)」[1]という世界はまだ遠いです。
コンポーネントとscssは1対1
これが一番の原則で、Some.tsx
とSome.module.scss
を1対1で関連付けることを守って欲しいです。 そうでないと途端に治安が悪化します。
# 例
src/path/Todo.module.scss
src/path/Todo.tsx
src/another-path/Header.module.scss
src/another-path/Header.tsx
...
冒頭の原則がプロジェククトに浸透するかはコンポーネント志向CSSがどれだけ共有できるかに依ります。SMACSSやFLOCSSなどの多機能なCSSクラスを統制して実装されたWebサイトやアプリケーションも普通に存在し、その選択肢も含めて方向性を認識する必要があります。
ネストは最小限に抑える
3重以上の親子・子孫セレクタを駆使するよりは粒度の小さいセレクタが好みです。言い換えれば、こちらの記事では「CSSがDOMを知っている」より「DOMがCSSを知っている」タイプ。
単にコーディング量を削減するためではなく、次のように「個別のスタイルよりも2つ揃って完成する」度合いが強いときに数段階のネストを適用します。
- ulに対するli、dlに対するdiv
- パーツ単位のUIに被せるための親スタイル
- その他、フクロウセレクタ等...
汎用クラスについて
CSSモジュールは「utility first」ではないですが、第2の選択肢として適度に取り入れると楽になります。ただし感覚的にはmixinで共通化し、汎用クラスは最小限にするのがベストな気がします。
composesは使わない
composesは共通クラスをセレクタに挿入して自動適用してくれる機能で、スタイルシートのファイルがDRYになります。プロセスは次のように、HTMLに共通クラスが当てられる結果になります。[2]
.common { /* ... */}
.primary {composes: common; /* ... */}
.danger {composes: common; /* ... */}
return <div className={styles.primary} />
// output: class="Foo_common_hash Foo_primary_hash"
return <div className={styles.danger} />
// output: class="Foo_common_hash Foo_danger_hash"
この隠蔽はさほど旨味を感じないので、混乱を避けるために使わなくていいと思っています。
CSS-in-JSをできるだけ入れない
動的なスタイルのpropsを受け取るコンポーネントを作りたくEmotion等を入れたくなるときが来ますが、スタイルの優先順位から一貫性が消えて狂う(※)ので可能な限り他のCSSライブラリを入れないことを推奨します。代わりにインラインCSS変数等を使うのがおすすめです。
※例えばビルドしてから初めてスタイルが崩れたりします
Discussion