Skip to the content.

スタイリング

目次

スタイリングを行うコンポーネントの追加

スタイリングの対象となるボタンコンポーネントを作りましょう。

以下のsrc/components/StyledButton.tsxを作成してください。 src/components/StyledButton.tsx

const StyledButton: React.FC = () => {
  return (
    <>
      <button>Push</button>
    </>
  );
};

export default StyledButton;

このボタンが画面に表示されるように、Appコンポーネントも変更しましょう。 src/App.tsx

import StyledButton from "./components/StyledButton";

function App() {
  return (
    <>
      <StyledButton />
    </>
  );
}

export default App;

また、viteでプロジェクトのテンプレートを作成した場合、デフォルトのスタイルindex.cssmain.tsxで読み込んでいるので、index.cssの中身は、空にしておきましょう。

src/index.css

/* empty */

npm run devを実行し、http://localhost:5173/をブラウザで開いてください。 以下のようなボタンが表示されます。

default button

Raw CSS

スタイリングのやり方について説明します。まずは、一番シンプルなcssファイルを読み取る方法です。

まず、cssを定義しましょう。以下のcssファイルを作成してください。 src/components/cutom-button.css

.custom-button {
  padding-top: 0.625rem;
  padding-bottom: 0.625rem;
  padding-left: 1.25rem;
  padding-right: 1.25rem;
  margin-bottom: 0.5rem;
  border-radius: 0.5rem;
  font-size: 0.875rem;
  line-height: 1.25rem;
  font-weight: 500;
  color: #ffffff;
  background-color: #1d4ed8;
}

.custom-button:hover {
  background-color: #1e40af;
}

.custom-button:focus {
  outline-style: solid;
  outline-width: 4px;
  outline-color: #93c5fd;
}

それでは、StyledButton.tsxのbutton要素にクラス名をつけましょう。htmlでは、通常classでクラス名を指定しますが、Reactでは、classがjavascriptのクラスと名前が被ってしまうため、classNameで指定します。

また、定義したcssも読み込む必要がありますので、cssファイルをimportしましょう。

StyledButton.tsxを以下のように修正しましょう。

src/components/StyledButton.tsx

import "./custom-button.css";

const StyledButton: React.FC = () => {
  return (
    <>
      <button className="custom-button">Push</button>
    </>
  );
};

export default StyledButton;

ブラウザを確認すると以下のようなボタンが表示されているはずです。 また、少し触ってみて、hoverやfocus時のスタイルも確認してみましょう。

styled button by css file

ただし、cssファイルを読み込ませた場合、グローバルに適用されます。そのため、全体に適用したいスタイルのみ記述するようにしましょう。

全体に適用したいスタイルは、このindex.cssに定義するようにし、main.tsxで読み込むようにしましょう。

各コンポーネントに適用するスタイルに、cssを使用することもできますが、このやり方だと名前の衝突が問題になります。もし、同じ名前のスタイルが定義されていた場合、後から読み込まれたスタイルが上書きされてしまいます。

各コンポーネントで使うスタイルは、以下で紹介するCSS Modules, CSS in JS, Tailwindのいずれかを利用してください。

style props

ReactでHTML要素を使う場合に、style propsを渡すことができます。このやり方だと、HTML要素に直接スタイルを記述するので、名前の衝突がありません。また、javascriptの変数も使うことができるので、動的なスタイルも適用できます。

style propsは以下のように適用します。StyledButton.tsxにボタンを追加し、cssで記述したスタイルをそのままstyle propsに記述していきます。コンポーネントを以下のように修正しましょう。

また、今後ボタンが複数並ぶので、みやすいようにgridも作成しています。

const StyledButton: React.FC = () => {
  return (
    <div
      style={{
        display: "grid",
        gridTemplateColumns: "repeat(4, minmax(0, 1fr))",
        gap: "1rem",
      }}
    >
      <button className="custom-button">Push</button>
      <button
        style={{
          paddingTop: "0.625rem",
          paddingBottom: "0.635rem",
          paddingLeft: "1.25rem",
          paddingRight: "1.25rem",
          marginBottom: "0.5rem",
          borderRadius: "0.5rem",
          fontSize: "0.875rem",
          lineHeight: "1.25rem",
          fontWeight: 500,
          color: "#ffffff",
          backgroundColor: "#1d4ed8",
          borderStyle: "none",
        }}
      >
        Push
      </button>
    </div>
  );
};

こうすることで、同じようなボタンが2つ並びます。

styled button by style props

ただし、style propsでは、hoverとfocusは、後で紹介する状態管理を使って行う必要があるので、ここでは適用していません。

style propsはパフォーマンスが悪いため、あまり多用しない方が良いでしょう。名前の衝突の回避や動的なスタイルの適用は、後に紹介する方法でもできます。

CSS Moldules

cssをそのまま使った場合にあった問題:名前の衝突を回避するために使われるのが、css modulesです。

css modulesでは、cssは通常通り記述するのですが、最終的に適用されるクラス名が自動生成されたものになるので、名前の衝突が回避できるようになります。

Raw CSSで作成したcssファイルと中身が同じものを用意します。 ファイル名は、custom-button.module.cssとしてください。cssの前にmoduleと入れることで、CSS Modulesとして認識してくれます。

以下のファイルを作成してください。

src/components/custom-button.module.css

.custom-button {
  padding-top: 0.625rem;
  padding-bottom: 0.625rem;
  padding-left: 1.25rem;
  padding-right: 1.25rem;
  margin-bottom: 0.5rem;
  border-radius: 0.5rem;
  font-size: 0.875rem;
  line-height: 1.25rem;
  font-weight: 500;
  color: #ffffff;
  background-color: #1d4ed8;
  border-style: none;
}

.custom-button:hover {
  background-color: #1e40af;
}

.custom-button:focus {
  outline-style: solid;
  outline-width: 4px;
  outline-color: #93c5fd;
}

それでは、作成したファイルを読み込んでいきましょう。 CSS Modulesでは、以下のようにimportして使います。

import styles from "./custom-button.module.css"

このimportしたstylesを見てみると

{"custom-button":"_custom-button_1317u_1"}

となっており、"_custom-button_1317u_1"は、自動生成されたクラス名です。したがって、styles["custom-button"]classNameに指定しましょう。

<button className={styles["custom-button"]}>Push</button>

StyledButton.tsxを以下のように修正しましょう。

src/components/StyledButton.tsx

import "./custom-button.css";
import styles from "./custom-button.module.css";

const StyledButton: React.FC = () => {
  return (
    <div
      style={{
        display: "grid",
        gridTemplateColumns: "repeat(4, minmax(0, 1fr))",
        gap: "1rem",
      }}
    >
      <button className="custom-button">Push</button>
      <button
        style={{
          paddingTop: "0.625rem",
          paddingBottom: "0.635rem",
          paddingLeft: "1.25rem",
          paddingRight: "1.25rem",
          marginBottom: "0.5rem",
          borderRadius: "0.5rem",
          fontSize: "0.875rem",
          lineHeight: "1.25rem",
          fontWeight: 500,
          color: "#ffffff",
          backgroundColor: "#1d4ed8",
          borderStyle: "none",
        }}
      >
        Push
      </button>
      <button className={styles["custom-button"]}>Push</button>
    </div>
  );
};

export default StyledButton;

npm run devを実行し、開発サーバーで実行結果を確認すると、同じボタンが3つ並ぶことが確認できます。

以上が、CSS Modulesの使い方です。cssの書き方は、変わらないので、すでにcssを使い慣れている人におすすめの方法です。

CSS Modulesの注意点

CSS Modulesは、css-loaderのメンテナーがCSS Moduleを非推奨にしたいと意思表明があり、近々非推奨になるのではないかと言われていたり、一方でNext.jsでは公式ドキュメントでCSS Moduleを推奨にするようにしたいと言うIssueが立てられたりなど、CSS Modulesが、今後どうなっていくのか不透明な状態です。

CSS Modulesの歴史、現在、これから - Hatena Developer Blog

ここからは、筆者個人の意見ですが、CSS Modulesは、cssに使い慣れている人にとっては、非常に強力なツールですので、既にcssで使い慣れている人は、使ってもいいかと思います。

逆にcssを使い慣れていない人は、次に紹介するCSS-in-JSやTailwindを使うのが安全かと思います。

CSS in JS

CSS-in-JSとは、外部ファイル(cssファイル)にスタイルを定義するのではなく、Javascriptにスタイルを定義するものです。

CSS-in-JSのメリット

CSS-in-JSのライブラリは、複数ありますが、ここでは、最も利用されているstyled-componentsを取り扱います。

styled-componentsについて

styled-componentsでは、以下の公式サイトのサンプルのように、HTML要素にスタイルをつけたものをコンポーネントとして定義することができるようになります。

import styled from "styled-components";

// Create a Title component that'll render an <h1> tag with some styles
const Title = styled.h1`
  font-size: 1.5em;
  text-align: center;
  color: #BF4F74;
`;

// Create a Wrapper component that'll render a <section> tag with some styles
const Wrapper = styled.section`
  padding: 4em;
  background: papayawhip;
`;

// Use Title and Wrapper like any other React component – except they're styled!
render(
  <Wrapper>
    <Title>
      Hello World!
    </Title>
  </Wrapper>
);

また、styled-compoentnsは、コンポーネントなので、以下のようにpropsを渡すこともでき、動的なスタイルも定義できます。

import styled from "styled-components";

const Button = styled.button<{ $primary?: boolean; }>`
  /* Adapt the colors based on primary prop */
  background: ${props => props.$primary ? "#BF4F74" : "white"};
  color: ${props => props.$primary ? "white" : "#BF4F74"};

  font-size: 1em;
  margin: 1em;
  padding: 0.25em 1em;
  border: 2px solid #BF4F74;
  border-radius: 3px;
`;

render(
  <div>
    <Button>Normal</Button>
    <Button $primary>Primary</Button>
  </div>
);

styled-componentsのインストール

それでは、styled-componentsをインストールしましょう。 プロジェクトのディレクトリに移動して、npmでインストールします。

cd vite-project
npm install styled-components

styled-componentsの利用

ここからstyled-componentsを実際に使っていくのですが、 styled-componentsは、javascriptにcssを記述するため、デフォルトだと予測変換やシンタックスハイライトが効かないので、拡張機能を入れると便利です。

まず、vscodeの拡張機能vscode-styled-componentsをインストールしましょう。

それでは、Raw CSSで定義したものと全く同じスタイルのボタンをstyled-componentsで作ってみましょう。

StyledButton.tsxに以下の記述を追加してください。

import styled from "styled-components";

const CustomButton = styled.button`
  padding-top: 0.625rem;
  padding-bottom: 0.625rem;
  padding-left: 1.25rem;
  padding-right: 1.25rem;
  margin-bottom: 0.5rem;
  border-radius: 0.5rem;
  font-size: 0.875rem;
  line-height: 1.25rem;
  font-weight: 500;
  color: #ffffff;
  background-color: #1d4ed8;
  border-style: none;

  &:hover {
    background-color: #1e40af;
  }

  &:focus {
    outline-style: solid;
    outline-width: 4px;
    outline-color: #93c5fd;
  }
`;

ここで、定義したCustomButtonStyledButtonコンポーネントに追加しましょう。

const StyledButton: React.FC = () => {
  return (
    <div
      style={{
        display: "grid",
        gridTemplateColumns: "repeat(4, minmax(0, 1fr))",
        gap: "1rem",
      }}
    >
      <button className="custom-button">Push</button>
      <button
        style={{
          paddingTop: "0.625rem",
          paddingBottom: "0.635rem",
          paddingLeft: "1.25rem",
          paddingRight: "1.25rem",
          marginBottom: "0.5rem",
          borderRadius: "0.5rem",
          fontSize: "0.875rem",
          lineHeight: "1.25rem",
          fontWeight: 500,
          color: "#ffffff",
          backgroundColor: "#1d4ed8",
          borderStyle: "none",
        }}
      >
        Push
      </button>
      <button className={styles["custom-button"]}>Push</button>
      <CustomButton>Push</CustomButton>
    </div>
  );
};

npm run devを実行し、開発サーバーで実行結果を確認すると、同じボタンが4つ並ぶことが確認できます。

以上が、styled-componentsの使い方です。CSS in JSは、styled-componentsの他にもEmotionLinariaなどがあります。

emotionは、styled-componentsを拡張したもので、styled-componentsと同じ記法も使えますが、以下のようにcssとcssというpropsに渡すことでもスタイルを定義することができます。

import { css } from '@emotion/react'

const color = 'white'

render(
  <div
    css={css`
      padding: 32px;
      background-color: hotpink;
      font-size: 24px;
      border-radius: 4px;
      &:hover {
        color: ${color};
      }
    `}
  >
    Hover to change color.
  </div>
)

また、Emotionは、Material UIでも使うことができるので、Material UIの利用を考えている場合は、Emotionを利用するのが良さそうです。

styled-componentsに拘らず、自分のニーズに合ったライブラリを利用しましょう。

Tailwind

Tailwindのメリット

Tailwindについて

tailwindは、cssだとdisplay: flex;を適用させたい場合は、クラス名にflexを指定していきます。

例えば、cssだと以下のような指定がしたい場合、

{
  display: flex; 
  padding-top: 0.75rem;
  padding-bottom: 0.75rem; 
  padding-left: 1rem;
  padding-right: 1rem; 
  align-items: center; 
  color: #ffffff; 
  background-color: #3B82F6;
}

:hover {
  background-color: #60A5FA; 
}

tailwindを利用すると以下をclassNameに指定することになります。

className="flex items-center px-4 py-3 text-white bg-blue-500 hover:bg-blue-400"

Tailwindのインストール

まず、Tailwindのインストール手順です。 公式サイトの案内は、こちらにあります。

まず、viteで作成したプロジェクトのディレクトリに移動します。

cd vite-project

次に、tailwindとその関連ライブラリをインストールします。

npm install -D tailwindcss postcss autoprefixer

次に、Tailwindの初期化処理を行います。

npx tailwindcss init -p

上記コマンド実行後、tailwind.config.jsというファイルが作成されるので、Tailwindを使うファイルを以下のように指定します。

/** @type {import('tailwindcss').Config} */
export default {
  content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
  theme: {
    extend: {},
  },
  plugins: [],
};

次にsrc/index.cssの先頭に以下の内容を追加します。

src/index.css

@tailwind base;
@tailwind components;
@tailwind utilities;

以上で、Tailwindが使えるようになります。

※Tailwindを利用する場合、デフォルトで設定されるスタイルは、すべてクリアされ、適用されません。

VSCodeの拡張機能のインストール

Tailwindは、独自の構文を使っているので、予測変換が効くようにVSCodeの以下の拡張機能をインストールしましょう。

Tailwind CSS IntelliSense

デフォルトの設定だと補完が遅いので、VSCodeの設定を変更します。setting.jsonに以下を追加してください。

setting.json

"editor.quickSuggestions": {
  "strings": true
}

Tailwindの利用

それでは、ここから実際にTailwindを利用していきましょう。

まず、デフォルトのスタイルが適用されなくなるので、見やすさのために、App.tsxを以下のように修正してください。

src/App.tsx

import StyledButton from "./components/StyledButton";

function App() {
  return (
    <div className="m-2">
      <StyledButton />
    </div>
  );
}

export default App;

それでは、Tailwindでこれまでと同じボタンを作っていきましょう。 Tailwindを使うと以下のようになります。

<button className="mb-2 me-2 rounded-lg bg-blue-700 px-5 py-2.5 text-sm font-medium text-white hover:bg-blue-800 focus:outline-none focus:ring-4 focus:ring-blue-300">
  Push
</button>

このボタンをStyledButton.tsxに追加します。

src/components/StyledButton.tsx

import "./custom-button.css";
import styles from "./custom-button.module.css";
import styled from "styled-components";

const CustomButton = styled.button`
  padding-top: 0.625rem;
  padding-bottom: 0.625rem;
  padding-left: 1.25rem;
  padding-right: 1.25rem;
  margin-bottom: 0.5rem;
  border-radius: 0.5rem;
  font-size: 0.875rem;
  line-height: 1.25rem;
  font-weight: 500;
  color: #ffffff;
  background-color: #1d4ed8;
  border-style: none;

  &:hover {
    background-color: #1e40af;
  }

  &:focus {
    outline-style: solid;
    outline-width: 4px;
    outline-color: #93c5fd;
  }
`;

const StyledButton: React.FC = () => {
  return (
    <div
      style={{
        display: "grid",
        gridTemplateColumns: "repeat(4, minmax(0, 1fr))",
        gap: "1rem",
      }}
    >
      <button className="custom-button">Push</button>
      <button
        style={{
          paddingTop: "0.625rem",
          paddingBottom: "0.635rem",
          paddingLeft: "1.25rem",
          paddingRight: "1.25rem",
          marginBottom: "0.5rem",
          borderRadius: "0.5rem",
          fontSize: "0.875rem",
          lineHeight: "1.25rem",
          fontWeight: 500,
          color: "#ffffff",
          backgroundColor: "#1d4ed8",
          borderStyle: "none",
        }}
      >
        Push
      </button>
      <button className={styles["custom-button"]}>Push</button>
      <CustomButton>Push</CustomButton>
      <button className="mb-2 me-2 rounded-lg bg-blue-700 px-5 py-2.5 text-sm font-medium text-white hover:bg-blue-800 focus:outline-none focus:ring-4 focus:ring-blue-300">
        Push
      </button>
    </div>
  );
};

export default StyledButton;

npm run devを実行してブラウザで確認してみましょう。

styled button by style props

Tailwindの自動並び替え(スキップ可)

Tailwindは、classNameにずらっとユーティリティクラスが並ぶ形になります。その際にユーティリティクラスの並び順がバラバラだと見づらくなってしまいます。

そこで、Tailwind公式がprettierのプラグインとしてTailwindのユーティリティクラスを並び替えしてくれる機能を開発しているので、Tailwindを使う場合は、これを導入しましょう。

公式の案内は、こちらです。

まず、以下のコマンドでprettierとprettierのプラグインを入れます。

npm install -D prettier prettier-plugin-tailwindcss

次に、prettierがプラグインを認識してくれるように、プロジェクトディレクトリに以下の内容の.prettierrcというファイルを作成してください。

.prettierrc

{
  "plugins": ["prettier-plugin-tailwindcss"]
}

Tailwindの注意点(動的なスタイル)

Tailwindで動的なスタイルを定義しようとした時に、うまくスタイルが反映されない場合があります。うまくいかない例とうまくいく例をみていきましょう。

うまくいかない例

App.tsxを以下のようにしてみましょう。

src/App.tsx

import StyledButton from "./components/StyledButton";

function App() {
  let marginSize = 4;
  return (
    <div className={`m-${marginSize}`}>
      <StyledButton />
    </div>
  );
}

export default App;

これで、npm run devでブラウザで実行結果を確認するとmarginが適用されていないはずです。

うまくいく例

今度は、App.tsxを少し変えて、以下のようにします。

src/App.tsx

import StyledButton from "./components/StyledButton";

function App() {
  let marginSize = "big";
  return (
    <div className={`${marginSize === "big" ? "m-4" : "m-2"}`}>
      <StyledButton />
    </div>
  );
}

export default App;

この違いが起こる理由は、tailwindのユーティリティクラスは、ソースコードを静的に解析を行い、そこで使用されているユーティリティクラスを検知し、実際のcssに反映させる仕組みになっています。

そのため、m-${marginSize}と記述するとTailwindのユーティリティクラスと一致しないため、実際のcssには反映されず、スタイルが適用されないのです。

まとめ

全体に適用するスタイルは、cssで記述しましょう。各コンポーネントで適用するスタイルは、CSS Modules, CSS in JS, Tailwindの中から自分に合ったものを選びましょう。

本資料では、Tailwind CSSを使っていきます。

Next: Chapter4 状態管理 useState

Prev: Chapter2 Reactの基本動作