Tips

なぜか効かない?ReactにおけるCSSの書き方の基本!module.cssが適用されない問題も解説

  • このエントリーをはてなブックマークに追加

「普通にCSSを書いているのに何故かスタイルが適用されないことがある」
「Reactって結局CSSをどのファイルに書くべきなのかがピンときていない」
「〇〇.cssと〇〇.module.cssって何が違うのかわからない」

本日はそんな方に向けてReactの基本的なCSSの書き方を解説していきます。

Reactはとても便利なライブラリなのでCSSの書き方は何パターンもあり、どの書き方を採用するかは会社やプロジェクトによってバラバラです。

いきなり全部の書き方を知っても混乱してしまうので、初学者の方に最低限知ってもらいたい2パターンの書き方に絞って説明していきます。

また動画もあるので必要に応じて活用してください。

ReactでCSSファイルを使う書き方

まず一番シンプルな方法として、CSSファイルを作成して書く方法です。

以下のようなコンポーネントがあったとします。

import React from "react";
import Student from "./Student";

const PropsBasic = () => {
  return (
    <div>
      <strong className="student__error">エラーです</strong>
      <Student name="田中太郎" age="19" gender="男" />
      <hr />
      <Student name="鈴木大介" age="19" gender="男" />
      <hr />
      <Student name="山田花子" age="18" gender="女" />
    </div>
  );
};

export default PropsBasic;
import React from "react";

const Student = ({ name, age, gender }) => {
  return (
    <div>
      <strong>
        情報の取得に失敗しました
      </strong>
      <h3>{name}</h3>
      <p>
        <span>{age}</span>歳
      </p>
      <p>{gender}</p>
    </div>
  );
};

export default Student;

Students.jsという親コンポーネントにStudent.jsという子コンポーネントを読み込んでいる状態です。

例えば子コンポーネントであるStudent.jsにCSSを当てたいとした場合、まずclassNameという属性をHTMLタグに追加します。

一般的なHTMLでいうclass属性に当たるものがReactではclassNameというものになります。

import React from "react";

const Student = ({ name, age, gender }) => {
  return (
    <div>
      {/* ここを追加  */}
      <strong className="student__error">
        情報の取得に失敗しました
      </strong>
      <h3>{name}</h3>
      {/* ここを追加  */}
      <p className="student__text">
        <span>{age}</span>歳
      </p>
    {/* ここを追加  */}
      <p className="student__text">{gender}</p>
    </div>
  );
};

export default Student;

あとはCSSファイルを新規作成して先ほどのclassNameで指定した場所にCSSをどんどん書いていくだけです。

.student__text {
  font-weight: bold;
}
.student__error {
  color: red;
}

通常のHTML、CSSでもあるようにCSSファイルは読み込みが必要です。

Reactの場合はimport文でCSSファイルを読み込むルールになっています。

import React from "react";
{/* ここを追加  */}
import "./cssBem/Student.css";

const Student = ({ name, age, gender }) => {
  return (
    <div>
      <strong className="student__error">
        情報の取得に失敗しました
      </strong>
      <h3>{name}</h3>
      <p className="student__text">
        <span>{age}</span>歳
      </p>
      <p className="student__text">{gender}</p>
    </div>
  );
};

export default Student;

こんな感じでWeb制作のようなスタイルでCSSを書く方法がまず最初に覚える書き方になるでしょう。

ちなみに今回のようにコンポーネントが親子関係になっている場合は、子コンポーネントでCSSファイルを読み込んでいれば親コンポーネントでも同じCSSファイルが使用できます。

試しに親コンポーネントのStudents.jsにも同じクラスを付与してみましょう。

import React from "react";
import Student from "./Student";

const PropsBasic = () => {
  return (
    <div>
      {/* ここを追加 */}
      <strong className="student__error">エラーです</strong>
      <Student name="田中太郎" age="19" gender="男" />
      <hr />
      <Student name="鈴木大介" age="19" gender="男" />
      <hr />
      <Student name="山田花子" age="18" gender="女" />
    </div>
  );
};

export default PropsBasic;

Students.jsではCSSのインポート文を書いていませんが、Student.jsで使った「.student__error」というクラス名を付与するとスタイルが適用されました。

これはStudents.jsでStudent.jsを読み込んでいて、Student.js内でCSSのインポートがされているため自動的に同じCSSが使えているためです。

一見便利なように見えますが、良いことばかりではありません。

例えばですが複数人で開発していたとして、クラス名が被ることで意図しないスタイルになる可能性があるからです。

チームでクラスの命名ルールを徹底すればOKですが覚えておきましょう。

ReactでCSSモジュールを使ったスタイルの書き方

続いて2個目の書き方としてCSSモジュールというものを紹介します。

こちらは初学者やWeb制作のみの経験者であれば馴染みのない言葉かと思います。

実際には先ほどのCSSファイルとほとんど変わりません。

まずファイル名を「〇〇.module.css」とするのがルールです。

.student__text {
  font-weight: bold;
}
.student__error {
  color: red;
}

インポート文については先ほどと少し違って以下のような書き方をします。

今回も子コンポーネントのStudent.jsで使用してみます。

import React from "react";
{/* ここを変更  */}
import styles from "./cssModule/Student.module.css";

const Student = ({ name, age, gender }) => {
  return (
    <div>
      <strong className="student__error">
        情報の取得に失敗しました
      </strong>
      <h3>{name}</h3>
      <p className="student__text">
        <span>{age}</span>歳
      </p>
      <p className="student__text">{gender}</p>
    </div>
  );
};

export default Student;

このようなインポート文はコンポーネントやフックの読み込みで使うものと同じ書き方ですね。

ファイルのパスと一緒にコンポーネント内での名前を決めます。

今回は「styles」という名前にしました。

続いてclassNameの書き方も以下のように変更することになります。

import React from "react";
import styles from "./cssModule/Student.module.css";

const Student = ({ name, age, gender }) => {
  return (
    <div>
      {/* ここを変更 */}
      <strong className={styles.student__error}>
        情報の取得に失敗しました
      </strong>
      <h3>{name}</h3>
      {/* ここを変更 */}
      <p className={styles.student__text}>
        <span>{age}</span>歳
      </p>
      {/* ここを変更 */}
      <p className={styles.student__text}>{gender}</p>
    </div>
  );
};

export default Student;

先ほどは通常のHTML、CSSと同じように文字列でクラス名を書いていました。

今回はオブジェクトの形にして「モジュール名 . クラス名」という書き方に変わります。

モジュール名というのはインポート文で決めた「styles」のことです。

propsや関数を埋め込む書き方に近いですね。

CSSファイルは変更していないので画面の状態は先ほどのままです。

いかがでしょう、書き方こそ違いますがそこまで難しくはないかと思います。

書籍や学習教材を見ているとCSSファイルと「〇〇.css」としているものと「〇〇.module.css」としているものがあって違いがわからなかったかもしれませんが、結局はクラス名を決めてCSSをそれぞれに書いているという点では一緒です。

1点違いがあるとすると親コンポーネントについてです。

実は親コンポーネントのStudents.jsにはCSSは当たっていません。

検証ツールを見ても、対象のクラスにはCSSファイルが表示されません。

よくよく考えてみるとCSSモジュールはclassNameの書き方が変わっていましたが、Students.jsについては変更していませんでしたね。

そこでStudents.jsの方も修正を加えましょう。

import React from "react";
import Student from "./Student";

const PropsBasic = () => {
  return (
    <div>
      {/* ここを変更 */}
      <strong className={styles.student__error}>エラーです</strong>
      <Student name="田中太郎" age="19" gender="男" />
      <hr />
      <Student name="鈴木大介" age="19" gender="男" />
      <hr />
      <Student name="山田花子" age="18" gender="女" />
    </div>
  );
};

export default PropsBasic;

しかしエラーになってしまいました。

これもよく考えてみれば当然の結果で、Students.jsではインポート文を書いていなくて「styles」なんて無いからです。

そこでStudents.jsにもインポート文を書いてみます。

import React from "react";
import Student from "./Student";
{/* ここを追加 */}
import styles from "./cssModule/Student.module.css";

const PropsBasic = () => {
  return (
    <div>
      <strong className={styles.student__error}>エラーです</strong>
      <Student name="田中太郎" age="19" gender="男" />
      <hr />
      <Student name="鈴木大介" age="19" gender="男" />
      <hr />
      <Student name="山田花子" age="18" gender="女" />
    </div>
  );
};

export default PropsBasic;

今回こそスタイルが適用されました。

このようにCSSモジュールはコンポーネントごとに必ずインポート文を書いて読み込む必要があるのです。

しかし今回の例はCSSモジュールの正しい使い方ではありません。

実務では同じCSSモジュールを複数のコンポーネントで読み込むことはほとんどしません。

CSSモジュールを使う場合はコンポーネントごとにファイル名を別々に分けます。

親コンポーネントのStudents.jsについて、新しいCSSモジュールStudents.module.cssを作りましょう。

先ほど使ったStudent.module.cssと同じコードを、新しく作ったStudents.module.cssにもコピーしておきます。

.student__text {
  font-weight: bold;
}
.student__error {
  color: red;
}

親コンポーネントであるStudents.jsのインポート文も修正しましょう。

import React from "react";
import Student from "./Student";
{/* ここを修正 StudentをStudentsに修正 */}
import styles from "./cssModule/Students.module.css";

const PropsBasic = () => {
  return (
    <div>
      <strong className={styles.student__error}>エラーです</strong>
      <Student name="田中太郎" age="19" gender="男" />
      <hr />
      <Student name="鈴木大介" age="19" gender="男" />
      <hr />
      <Student name="山田花子" age="18" gender="女" />
    </div>
  );
};

export default PropsBasic;

ブラウザの表示結果は同じになるのですが、検証ツールを確認すると不思議なことに気付きます。

クラス名が自分でつけたものではない名前になっています。

 「student__error」としていたものが「Student_student__error__cx758」となりました。

こちらはCSSモジュールの効果で自動でクラス名を付与してくれるのです。

自動でクラス名を付与してくれることでクラス名の被りを回避できます。

現状Students.jsとStudent.jsでは同じ「student__error」というクラス名を使い回しています。

例えば新しく作ったStudents.module.cssの方で色を赤から青に変えてみます。

.student__text {
  font-weight: bold;
}
/* ここを変更 */
.student__error {
  color: blue;
}

なんと同じクラス名を使っているのに、それぞれ赤色と青色で共存できています。

通常のHTML、CSSではクラス名が被って中身が違う場合は、優先順位や読み込み順によってどちらかに統一されてしまいますよね。

先ほど検証ツールで確認したようにCSSモジュールでは仮に同じクラス名を付けていたとしても、自動でユニークなクラス名に変わるためブラウザ上では問題にならないわけです。

一見CSSモジュールの方が面倒に見えますが実は便利な側面も持っていました。

このようにReactではCSSの書き方で書き方や動作が変わることがわかりました。

本記事で紹介した2パターン以外にもCSSの書き方はありますが、初学者の方はシンプルなCSSとCSSモジュールの2パターンだけ覚えてもらえれば大丈夫でしょう。

また今回参考にした書籍は以下になりますので必要な方はどうぞ

今回の記事を作成するのに参考にした本はこちらから

  • このエントリーをはてなブックマークに追加