CSS ModulesでCSSを書く時に実務で必要になる書き方まとめ

このサイトのCSSはこれまでstyled-jsxだったのですが、Gatsbyを2から3にアップグレードしたのを機に、CSS Modulesに置き換えました。

置き換える過程で、実務で必要になりような要件をどのようにクリアしていくのか体感できたので、まとめてみます。

以下、GatsbyでSCSSを利用したCSS Modulesのサンプルになります。

基本形

import * as styles from './index.module.scss';

<div className={styles.classA}></div>

マルチクラス or モディファイア

テンプレートリテラルを使って書きます。

<div className={`${styles.classB} ${styles.classC}`}></div>

ユーザースタイルシートとかを想定して、固定のclass名を付与するなら普通に書けばOKとのこと。

<div className={`classD ${styles.classE} ${styles.classF}`}></div>

条件付き

<div className={`${styles.classG}` ${isApply ? styles.classH : ''}`}></div>

インターネットではclassnamesclsxを推奨する記事を見ますが、モディファイアがつくとしてもせいぜい1つか2つでしょうから、素朴にテンプレートリテラルで書けば十分と考えます。

class名にハイフンが含まれている場合

ハイフンが含まれているclass名にはそのまま書けないので、括弧で囲います。

失敗する例:

<div className={styles.class-i}></div>

成功する例:

<div className={styles['class-i']}></div>

ハイフンは使わずにアンダースコア _ を使うようにすれば、これを気にせずに書けそうです。

ダイナミックなクラス名

テンプレートリテラルで書きましょう。

<div className={styles[`class${variantJ}`]}></div>

ダイナミックなクラス名にハイフンを含む場合は、ハイフンを含めないで書くと成功しました。こういうSCSSがある時に…

.hyphen-1 { ... }
.hyphen-2 { ... }

失敗する例:

<div className={styles[`hyphen-${variantK}`]}></div>

成功する例:

<div className={styles[`hypehn${variantK}`]}></div>

DOMに付与されるclassにはいい感じにハイフンが付いていました。

ハイフンは厄介ですね……。アンダースコアに寄せるのが分かりやすいかもしれません。

以上を合体したもの

合体してすこし複雑になった例です:

<div className={`classK ${styles.classL} ${isApply ? styles[`class${variantM}`] : ''}`}></div>

続きまして、CSS編です。

メディアクエリ

こんなmixinを入れたファイルを作って、必要なファイルでincludeします。

// mixins.scss

@use 'sass:map';

$breakpoints: (
  "sm": "(min-width: 577px)",
  "md": "(min-width: 769px)",
  "lg": "(min-width: 993px)",
);

@mixin mq($breakpoint) {
  @media screen and #{map.get($breakpoints, $breakpoint)} {
    @content;
  }
}
// index.scss

@use './mixins';

@include mixins.mq(md) {
  ...
}

ずっとCSS in JS脳になっていたおかげで、素朴にSASSの@useをすれば良いだけというところに辿り着くのに時間がかかってしまいました。灯台下暗しでした。

グローバルセレクタ

グローバルセレクタは使わずに作れたら理想ですが、いちおう使えます。

.container {
  :global(.children) {
    ...
  }
}

タグ名はそもそもスコープ付きでグローバルなようです。

.container {
  div {
    ...
  }
}