この記事が役立つかもしれない人
- コンポーネントごとに CSS を書きたい人
- 他のコンポーネントの CSS との重複を気にせず CSS を書きたい人
- React で Svelte のようなスタイル定義の体験をしたい人
状況
現在の問題点
Vite + React という構成で開発を行っており、以下のような問題に直面しました。
// 下記の CSS で Example コンポーネントのスタイルを定義している
import "./style.css"
const Example = () => {
return (
{/* text という名前のクラスが他の CSS で定義されていると干渉してしまう */}
<p className="text">これは例です</p>
);
}
問題の具体例
異なるコンポーネントで同じクラス名を使用すると意図しないスタイルの干渉が発生します。
例えば text
クラスが異なるスタイルを持つ複数のコンポーネントで定義されている場合、どのようにスタイルが適用されるかが予測困難になります。
今回はこの問題を解決するために CSS Modules を導入し、各コンポーネントのスタイルを独立させることにしました。
CSS Modules の概要とメリット
CSS Modules は各コンポーネントごとにスコープされた CSS を提供する手法です。
これによりクラス名の衝突を防いでコンポーネントごとのスタイルを独立させることができます。
CSS Modules の導入
Vite + React 環境の設定
まず Vite + React プロジェクトをセットアップします。
# Vite プロジェクトの作成
npm create vite@latest my-project --template react
# プロジェクトディレクトリに移動
cd my-project
# 依存関係のインストール
npm install
CSS Modules の設定
Vite では CSS Modules がデフォルトでサポートされています。そのため CSS ファイルの拡張子を .module.css
とするだけで利用可能です (.module.scss
でも可)。
しかし example-text
のようにハイフン付きでスタイルを書いている場合、React の className に適用しようとするとエラーを吐きます。
なのでハイフン付きクラスをキャメルケースでも呼び出せるように設定しておきます。
export default defineConfig({
plugins: [react()],
css: {
modules: {
localsConvention: 'dashes',
}
}
});
これで example-text
クラスを定義していた場合、React からは exampleText
として呼び出せます。
実装例
CSS Modules を使用した具体例です。
// モジュールオブジェクトを受け取る
import styles from "./style.module.css"
const Example = () => {
return (
{/* style.module.css で定義した text クラスを使う */}
<p className={styles.text}>これは例です</p>
);
}
型宣言ファイルの作成
TypeScript を使用している場合、CSS Modules の型宣言が必要です。
プロジェクトのルートディレクトリまたは src
フォルダ配下などに vite-env.d.ts
ファイルを作成して以下の内容を追加します。
/// <reference types="vite/client" />
declare module '*.module.css' {
const classes: { [key: string]: string };
export default classes;
}
さらに tsconfig.json
を編集して型宣言ファイルを含めます。
{
"compilerOptions": {
"...省略..."
},
"include": ["src/**/*", "vite-env.d.ts"]
}
実装結果の確認
実際にビルドされた CSS の確認
CSS Modules を使用してビルドした結果、以下のようにクラス名が一意に変更されます。
._text_jaca6_10 { color: red; }
._text_svqqv_15 { font-size: 32px; }
これにより異なるコンポーネントで定義された同名のクラス (例だと text
) が干渉することなく使用できます。
CSS Modules に関する設定オプション
Vite では CSS Modules に関する詳細な設定オプションが提供されています。
以下のように vite.config.ts
にオプションを追加することでカスタム設定が可能です。
export default {
css: {
modules: {
// CSS をローカルにスコープするデフォルトの挙動
scopeBehaviour: 'local',
// 例外としてグローバルスコープにしたいパス
globalModulePaths: [/global/],
// クラス名の生成ルールを設定
generateScopedName: '[name]__[local]___[hash:base64:5]',
}
}
}
この他にもオプションがあるため、詳しくは次のリンクを参照して下さい。
まとめ
CSS Modules を導入することでクラス名の衝突を防ぎ、各コンポーネントのスタイルを独立させることができました。
それによりスタイルの管理が容易となり、予期せぬスタイルの干渉も解消されてストレスが減りました!
この記事が役に立ったら 🩷 を頂けると嬉しいです!
参考資料