CSS

このサイトで CSS Modules を使っている理由

CSSが増えてくると、どこで定義したクラスがどこに効いているのか分からなくなります。名前が衝突する、消していいのか判断できない、上書きのために !important が増える。Tailwind はその答えのひとつですが、このサイトでは CSS Modules を選びました。理由を書いておきます。

何をしてくれるのか

CSS Modules は、クラス名をビルド時にファイル単位で一意な名前へ書き換えます。.button と書いても、実際に出力されるのは Button_button__x7f2a のような名前です。

別のコンポーネントで同じ .button を使っても衝突しません。名前空間を人間が管理しなくてよくなる、というのが本質です。

書き方

Button.module.css を作って、

.button { padding: 0.75rem 1.5rem; font-weight: 500; color: #fff; background: #0b57d0; border: none; border-radius: 999px; cursor: pointer; transition: background-color 0.2s ease; } .button:hover { background: #0a4fbb; }

styles 経由で参照します。

import styles from './Button.module.css'; export default function Button({ text }: { text: string }) { return <button className={styles.button}>{text}</button>; }

styles.button の中身はただの文字列です。存在しないクラスを参照しても undefined が入るだけでエラーにならないので、タイポに気づきにくいのが弱点です。型定義を生成しておくと防げます。

選んだ理由

一番大きいのは、CSS を CSS のまま書けることです。@keyframes::before、メディアクエリ、:has() まで、覚えた通りの構文がそのまま通ります。ユーティリティクラスの語彙に翻訳する手間がありません。

マークアップが読みやすいままなのも効いています。className={styles.card} の一語で済むので、JSX を開いたときに構造のほうが先に目に入ります。

向いていないところ

コンポーネントをまたいで余白やサイズを揃えたい場面には向きません。スコープが閉じている以上、共有したい値はどこかに置く必要があります。

このサイトでは CSS 変数を globals.css に集約して、各モジュールから var(--md-shape-md) のように参照しています。結局、スコープを閉じる仕組みと、共有する値を置く場所は別々に要る、というのが使ってみての結論でした。