第53章:CSS Modules
この章では、 「コンポーネントごとにCSSを分けて、キレイ&安全にスタイルを当てる」 ための仕組み、CSS Modules を使えるようになるのがゴールです ✨
53-1. まずはイメージから:なんで「部品ごと」にCSS?🤔
これまでのCSSって、こんな感じでしたよね:
index.cssにスタイルをどんどん足していく.titleとか.buttonとか、けっこう適当なクラス名- 別の画面でも
.buttonをつけたら、意図せずスタイルが変わっちゃう…😱
つまり、全部が「ひとつの大きなプール」みたいな状態なんです。
CSS Modules を使うと、こんなイメージになります ⬇️
Button.tsxは Button用のCSSだけ を見るCard.tsxは Card用のCSSだけ を見る- お互いのクラス名がかぶってもOK(
containerが両方にあっても平気)🎉
53-2. CSS Modulesってなに?ざっくり定義 💡
CSS Modules = 「CSSファイルを import して、オブジェクトみたいに使える仕組み」 です。
例えば:
-
Button.module.cssにクラスを定義/* src/components/Button.module.css */
.button {
padding: 8px 16px;
border-radius: 999px;
border: none;
font-weight: bold;
cursor: pointer;
}
.primary {
background-color: #ff66a3;
color: white;
} -
Reactコンポーネントで
import styles from './Button.module.css'として使う// src/components/Button.tsx
type ButtonProps = {
label: string;
};
export function Button({ label }: ButtonProps) {
return (
<button className={`${styles.button} ${styles.primary}`}>
{label}
</button>
);
}
ここでポイント ✨
-
stylesは「クラス名 → 実際のクラス文字列」のマップ(オブジェクト) -
styles.buttonやstyles.primaryが、それぞれ 実際のクラス名文字列 になります -
実際のHTMLでは、例えばこんな感じのクラスになります:
<button class="button_abc123 primary_def456">...</button>みたいに、ビルド時にユニークな名前に変わります(ハッシュ付き)🧬 だから 他のコンポーネントと絶対かぶらない のです 💪
53-3. Vite + React でのCSS Modulesのルール 📝
Vite の React テンプレでは、最初からCSS Modulesが使える設定になっています。 ただし、いくつかルールがあります:
-
ファイル名は
*.module.cssにするButton.cssではダメButton.module.cssならOK(これで「モジュールとして扱うよ」と教える)
-
React 側では
import styles from './Button.module.css'stylesという名前は慣習だけど、ほとんどの人がそう書くのでマネしてOK👌
-
JSX側では
classではなく、classNameを使う- これは普通のReactのルール(おさらい 💡)
53-4. 実践:カワイイ「タグ風ボタン」を作ってみよう 💅
小さい実験として、タグっぽいボタンコンポーネントを作ってみましょう 🌸
① フォルダとファイルの用意
src/components フォルダに、次の2つを作ります:
TagButton.tsxTagButton.module.css
② CSS Modules ファイルを書く(TagButton.module.css)
/* src/components/TagButton.module.css */
.tagButton {
display: inline-block;
padding: 4px 10px;
border-radius: 999px;
border: 1px solid #ff99c8;
font-size: 14px;
color: #ff4d94;
background-color: #fff0f7;
cursor: pointer;
transition: transform 0.1s ease, box-shadow 0.1s ease;
}
.tagButton:hover {
transform: translateY(-1px);
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08);
}
.tagButton:active {
transform: translateY(0);
box-shadow: none;
}
③ コンポーネントファイルを書く(TagButton.tsx)
// src/components/TagButton.tsx
import styles from "./TagButton.module.css";
type TagButtonProps = {
label: string;
};
export function TagButton({ label }: TagButtonProps) {
return <button className={styles.tagButton}>#{label}</button>;
}
ポイント 🎯
-
import styles from "./TagButton.module.css";- この1行で、CSSファイルがオブジェクトとして読み込まれるイメージ
-
styles.tagButton- CSSの
.tagButtonクラスに対応
- CSSの
-
JSXの
classNameにセットすると、- 実際のHTMLではユニークなクラス名になる(他と衝突しない)
53-5. 仕組みのイメージを図で見てみよう 🧠✨
ビルド(npm run dev 中の裏側)で、だいたいこんなことが起きています:
- 開発中は
styles.tagButtonとだけ覚えておけばOK - 本番用のHTMLでは、長いクラス名に変身しているけど、意識しなくて大丈夫です🙆♀️
53-6. 複数クラスを組み合わせたいとき 🧩
CSS Modules でも、もちろんクラスを2つ以上つけられます。
さっきの Button.module.css を使って、こんな書き方もよくします:
// 例:primaryとoutlineの両方をつけるパターン
<button className={`${styles.button} ${styles.primary}`}>
送信する
</button>
もしくは、配列+join で書く人もいます:
<button className={[styles.button, styles.primary].join(" ")}>
送信する
</button>
どちらでもOKなので、自分が読みやすい方で大丈夫です 💖
53-7. TypeScript的にはどう扱われてるの?🧐
Vite の React + TS テンプレートでは、だいたいこんな感じの型が用意されています(イメージ):
// ざっくりイメージ
declare module "*.module.css" {
const classes: { [key: string]: string };
export default classes;
}
つまり、styles の型はだいたい:
{ [className: string]: string }
という「文字列キー → 文字列」のオブジェクトです。
ここでのポイント
-
styles.xxxと打つと、VS Code が存在するクラス名をサジェストしてくれることが多いので、とても楽 ✨ -
万が一、タイポすると
styles.tagButon(nが抜けてる)みたいになって、- 実行時に
undefinedが入ってクラスが当たらない → 見た目がおかしい
- 実行時に
-
なので、エディタの補完をちゃんと使うクセをつけるのがオススメです 🎓
53-8. よくあるつまづきポイント&チェックリスト ✅
CSS Modules を初めて使うときに「あるある」なミスをまとめておきます👇
❌ その1:ファイル名が .module.css じゃない
Button.css ← これだと「普通のCSS」
Button.module.css ← これならOK
ファイル名に module を入れ忘れると、オブジェクトとして import できません。
❌ その2:class を使っている
// ❌ よくある間違い
<button class={styles.button}>送信</button>
// ✅ 正しくは
<button className={styles.button}>送信</button>
React では className を使うのを忘れずに 🌟
❌ その3:パスが微妙に違う
import styles from "./Tagbutton.module.css"; // ❌ ファイル名と大文字小文字が違う
import styles from "./TagButton.module.css"; // ✅ OSに関係なく、ちゃんと一致させる!
VS Code の「ファイル名を右クリック → パスのコピー」や、 自動補完で選ぶようにすると安全です 🛟
53-9. ミニ練習:App.tsx にCSS Modulesを導入してみよう ✏️💕
ここからは「自分の手でやってみる」コーナーです!
ゴール
-
App.tsxの見た目を、CSS Modulesだけで整える -
ざっくりこんな雰囲気を目指します:
- 画面中央にカードっぽいボックス
- タイトル
- 説明文
- さっき作った
TagButtonを1つ表示
ステップ1:App.module.css を作成
src/App.module.css を新規作成して、こんな感じにしてみましょう(好きにアレンジしてOKです💗)
/* src/App.module.css */
.appRoot {
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
background: linear-gradient(135deg, #ffe5f0, #e3f2ff);
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
}
.card {
background-color: white;
padding: 24px 28px;
border-radius: 16px;
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.08);
text-align: center;
max-width: 480px;
width: 90%;
}
.title {
font-size: 24px;
margin-bottom: 8px;
color: #ff4d94;
}
.description {
font-size: 14px;
color: #555;
margin-bottom: 16px;
}
ステップ2:App.tsx からCSS Modulesを読み込む
src/App.tsx を開いて、ざっくり次のように書き換えてみます(※ プロジェクトの元のコードに合わせて調整してくださいね)
// src/App.tsx
import styles from "./App.module.css";
import { TagButton } from "./components/TagButton";
export function App() {
return (
<div className={styles.appRoot}>
<div className={styles.card}>
<h1 className={styles.title}>React & CSS Modules 入門 🌸</h1>
<p className={styles.description}>
このカード全体の見た目は、App.module.css にだけ書かれています。
他の画面とはケンカしない、平和なスタイリングです ✌️
</p>
<TagButton label="css-modules" />
</div>
</div>
);
}
ステップ3:ブラウザで確認 👀
npm run dev をして、ブラウザで確認してみましょう。
- 背景がグラデーションになっているか
- カードが中央に表示されているか
- タイトル・説明文・タグボタンが、それっぽくスタイルされているか
うまくいっていたら、CSS Modules デビュー成功です🎉🎉🎉
53-10. この章のまとめ 🐣
この章で学んだことをおさらいしておきましょう ✨
-
CSS Modules は、コンポーネントごとにCSSを分けて安全に管理できる仕組み
-
ファイル名は必ず
*.module.cssにする -
import styles from "./Xxx.module.css";で読み込んで、className={styles.someClass}として使う
-
実際のクラス名はビルド時にユニークになるので、
- 他のコンポーネントとクラス名がかぶってもOK👌
-
ちょっとしたデザインでも、「部品専用CSS」 を意識すると、プロっぽいコードに近づきます ✨
次の 第54章 では、 CSS Modules の「使い方とイイところ」を、もう少し深掘りしていきます。 「この書き方、現場だとどう使うの?」みたいな話もしていきましょう 🧑💻💖