React

【React】スタイリング方法まとめ

この記事の目次
  1. Reactでhtmlをスタイリングする方法
  2. CSSファイルを外部ファイルとして読み込む
  3. Sample.css
  4. Sample.js
  5. CSSファイルを外部ファイルとして読み込むメリット・デメリット
  6. インラインスタイル
  7. インラインスタイルのメリット・デメリット
  8. CSS Modules(近い将来廃止されるかも?)
  9. Sample.module.css
  10. Sample.js
  11. CSS Modulesのメリット・デメリット
  12. CSS in JS(styled-components)
  13. ライブラリ:styled-componentsをインストール
  14. Sample.js
  15. 継承を使って同じようなスタイルのボタンを作成する
  16. ネストが可能
  17. CSS in JSのメリット・デメリット

Reactでhtmlをスタイリングする方法をまとめました。

Reactでhtmlをスタイリングする方法

大きく以下の4つの方法があります。

  • CSSファイルを読み込む
  • インラインスタイル
  • CSS Modules
  • CSS in JS

それぞれの違いと特徴をみてみましょう。

CSSファイルを外部ファイルとして読み込む

外部ファイルとしてcssを読み込む方法は、とてもよく使う方法の一つです。
基本的には、jsファイル、つまりコンポーネントと同じ名前にしてcssファイルを作成します。
Sample.jsなら、Sample.cssとします。

Sample.css

.btn {
  width: 200px;
  height: 60px;
  display: block;
  font-size: 18px;
  line-height: 1.75;
  letter-spacing: 0.05em;
  cursor: pointer;
  color: black;
  border: none;
}
.btn.isSelected {
  background-color: black;
  color: white;
  border: 2px solid orange;
}

このような内容を記述したとします。
普通のcssです。

Sample.js

import { useState } from "react"
import './Sample.css';

const Sample = () => {
    const [isSelected, setIsSelected] = useState(false);

    const clickHandler = () => setIsSelected(prev => !prev);

    return (
        <>
            <button className={isSelected ? "btn isSelected" : "btn"} onClick={clickHandler}>Button</button>
            <button  className={`btn ${isSelected ? "isSelected" : ""}`} onClick={clickHandler}>Button2</button>
        </>
    )
};

export default Sample;

外部ファイルの場合、class属性は、ReactではclassNameとします。
テンプレートリテラル“を使う場合は、その中身は通常のjsを記述できるので、テンプレートリテラルの記法にのっとって${}で記述します。
コンポーネントごとに適用されないので、注意が必要です。
コンポーネントを意識した設計が必要になります。
画面全体に適用したいcssや共通のcssの場合には最適ですが、コンポーネントごとにcssを当てたいときは、CSS ModulesやCSS in JSを使います。

CSSファイルを外部ファイルとして読み込むメリット・デメリット

グローバルスコープになるので、CSSの詳細度は要注意です。
ルートファイルなど、共通のスタイルを適用させたい場所には最適です。

インラインスタイル

import { useState } from "react"

const Sample = () => {
    const [isSelected, setIsSelected] = useState(false);

    const clickHandler = () => setIsSelected(prev => !prev);
    const style = {
        width: 200,
        height: 60,
        display: "block",
        fontSize: 18,
        lineHeight: 1.75,
        "letter-spacing": "0.05em",
        cursor: "pointer",
        backgroundColor: isSelected ? "black" : "",
        color: isSelected ? "white" : "black",
        border: isSelected ? "2px solid orange": "none"
    }

    return (
        <>
            <button style={style} onClick={clickHandler}>Button</button>
            <button style={{backgroundColor: "red", color: "white"}}>Button2</button>
        </>
    )
};

export default Sample;

インラインスタイルでスタイルをあてるには、上記の2つの方法があります。
基本的にはJavaScriptの記法に沿う必要があるため、ケバブケース(background-color)といったcssの書き方ではなく、キャメルケース(backgroundColor)という書き方をします。
ケバブケースで書く場合は、””で囲むことで可能になります。
三項演算子で””を指定した場合、そのプロパティは設定していないことになります。
ただの数値を入れた場合pxになるので、pxは省略することができます。
どちらもインラインスタイル特有の問題がでてきます。
同じスタイルを当てたい場合、同じものを属性で指定しないといけません。
また、beforeのような疑似要素やactiveのような疑似セレクターはこの方法では記述できません。
あとは、@mediaなどのメディアクエリも使えません。
よって現実的にはメインでは使えません。
また、読み込むたびにスタイルが計算されるため、パフォーマンスもよくありません。

よって、基本的には、本番環境で使うことはほとんどありませんが、ちょっと当てて確認したいといった
テスト環境ではたまに使う方法となります。

インラインスタイルのメリット・デメリット

再利用性が低く、疑似要素やメディアクエリは使用できず、
レンダリングのたびに計算されてパフォーマンスも低下されるため、基本的にあまり使わないです。
ただし、動的に頻繁に計算が必要なスタイルのときや、テスト環境でちょっと試したいといったケースで使えます。

CSS Modules(近い将来廃止されるかも?)

Sample.module.css

.btn {
  width: 200px;
  height: 60px;
  display: block;
  font-size: 18px;
  line-height: 1.75;
  letter-spacing: 0.05em;
  cursor: pointer;
  color: black;
  border: none;
}
.btn:hover {
  background-color: blue;
}
.isSelected {
  background-color: black;
  color: white;
  border: 2px solid orange;
}

まず、CSS Modulesを使う場合、cssファイルは、module.cssとします。
あとは、メディアクエリも擬似要素なども普通のCSSと同じように記述可能です。
htmlタグを指定したりすると、共通のcssとしてスタイルが適用されてしまう点に注意が必要です。
divタグなどhtml要素に指定せず、cssクラスを使います。

Sample.js

import { useState } from "react"
import styles from './Sample.module.css';

const Sample = () => {
    const [isSelected, setIsSelected] = useState(false);
    console.log(styles);
    const clickHandler = () => setIsSelected(prev => !prev);

    return (
        <>
            <button className={isSelected ? styles.btn+" "+ styles.isSelected : styles.btn} onClick={clickHandler}>Button</button>
            <button  className={`${styles.btn} ${isSelected ? styles.isSelected : ""}`} onClick={clickHandler}>Button2</button>
        </>
    )
};

export default Sample;

基本的に問題はないのですが、将来的に廃止される可能性の高い記法になります。
よって、今から使う場合は極力CSS Modulesの使用はされて、下のCSS in JSなどを使うのがいいです。

CSS Modulesのメリット・デメリット

外部ファイルの読み込みと違い、クラス名の衝突は起きないのでCSSの詳細度などは気にせず記述できます。
CSSとJSが分かれる必要があります。これは好みの問題となります。
大きなデメリットとしては、React開発側が廃止したい旨をつぶやいているので、
将来的に廃止、もしくは非推奨になる可能性が高い点です。

CSS in JS(styled-components)

CSS in JSは、基本的には、ライブラリを使用します。
有名なライブラリとして、styled-componentsや、emotionsがあります。

ライブラリ:styled-componentsをインストール


npm i styled-components

上のようにしてインストールします。
VS Codeを使っている場合は、拡張機能(styled-components.vscode-styled-components)を入れておくとハイライトされて便利です。

Sample.js

import { useState } from "react";
// import styles from './Sample.module.css';
import styled from "styled-components";
//   const StyledBtn = styled.button``;// タグ付きテンプレート、関数の実行と同じ、最初は大文字で書く
const StyledBtn = styled.button`
  /* この中はcssと全く同じ記法 */
  width: 200px;
  height: 60px;
  display: block;
  font-size: 18px;
  line-height: 1.75;
  letter-spacing: 0.05em;
  cursor: pointer;
  color: black;
  border: none;
  /* propsを渡すときは関数にする */
  background-color: ${(props) => (props.isSelected ? "black" : "white")};
  /* 分割代入でも記述可能 */
  color: ${({ isSelected }) => (isSelected ? "white" : "black")};
`;

const Sample = () => {
  const [isSelected, setIsSelected] = useState(false);
  const clickHandler = () => setIsSelected((prev) => !prev);

  return (
    <>
      <StyledBtn isSelected={isSelected} onClick={clickHandler}>
        Button
      </StyledBtn>
    </>
  );
};

export default Sample;

上のように記述します。
StyledBtnというコンポーネントとして使用することができます。

ポイントとしては、

const StyledBtn = styled.button``;// タグ付きテンプレート、関数の実行と同じ、最初は大文字で書く

タグ付きテンプレートという記法を使います。
テンプレートリテラル“部分を実行するという関数になります。
このテンプレートリテラル部分に普通のCSSを記述していきます。
テンプレートリテラルなので、基本的には文字列になります。JSを使いたい部分だけ、テンプレートリテラルの記法にのっとり、${}で記述します。
コンポーネントと同じため、propsを渡すことが可能です。

  /* propsを渡すときは関数にする */
  background-color: ${(props) => (props.isSelected ? "black" : "white")};
  /* 分割代入でも記述可能 */
  color: ${({ isSelected }) => (isSelected ? "white" : "black")};

継承を使って同じようなスタイルのボタンを作成する

import { useState } from "react";
// import styles from './Sample.module.css';
import styled from "styled-components";
//   const StyledBtn = styled.button``;// タグ付きテンプレート、関数の実行と同じ、最初は大文字で書く
const StyledBtn = styled.button`
  /* この中はcssと全く同じ記法 */
  width: 200px;
  height: 60px;
  display: block;
  font-size: 18px;
  line-height: 1.75;
  letter-spacing: 0.05em;
  cursor: pointer;
  color: red;
  border: none;
  /* propsを渡すときは関数にする */
  background-color: ${(props) => (props.isSelected ? "black" : "white")};
  /* 分割代入でも記述可能 */
  color: ${({ isSelected }) => (isSelected ? "white" : "black")};
`;

const RedBtn = styled(StyledBtn)`
  background-color: ${(props) => (props.isSelected ? "gray" : "red")};
  :hover {
    opacity: 0.8;
  }
  span {
    color: blue;
    font-weight: bold;
  }
`;
const Sample = () => {
  const [isSelected, setIsSelected] = useState(false);
  const clickHandler = () => setIsSelected((prev) => !prev);

  return (
    <>
      <StyledBtn isSelected={isSelected} onClick={clickHandler}>
        Button
      </StyledBtn>
      <RedBtn isSelected={isSelected} onClick={clickHandler}>
        Button<span>スパン</span>
      </RedBtn>
    </>
  );
};

export default Sample;

上のように、styled-componentを継承することが可能です。

const RedBtn = styled(StyledBtn)``;

具体的には上のように、継承したいstyled-componentをstyledの引数にわたします。
あとは、テンプレートリテラル部分に、変更したい内容を記述します。

ネストが可能

上のように、ネストして書くことが可能です。
そのため、基本的にコンポーネントごとに記述することができます。

あとは、メディアクエリも擬似要素も疑似セレクターもCSSはすべて記述可能です。
ランダムな文字列が付与されるようになるため、CSSの詳細度はもはや気にしなくてよくなります。

CSS in JSのメリット・デメリット

クラス名の衝突は起きないので詳細度は気にしなくていいです。
CSSとJSが一つにまとまります。これは好みの問題です。
propsを参照して動的にスタイルを当てることができます。
疑似要素やメディアクエリなどCSSの機能なすべて使用可能です。
ライブラリは入れる必要があります。
とりわけデメリットがあるわけではありませんが、記述の仕方に慣れが必要となります。
現在主流の書き方となります。