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

React

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の機能なすべて使用可能です。
ライブラリは入れる必要があります。
とりわけデメリットがあるわけではありませんが、記述の仕方に慣れが必要となります。
現在主流の書き方となります。

React

Posted by devsakaso