RalaCode
menusearch

【React】Emotionの使い方【基本から応用まで解説】

  • React
【React】Emotionの使い方【基本から応用まで解説】
  • 「React開発でEmotionを導入したい」

  • 「styled-componentsより使える?」

  • 「TypescriptでEmotionを使いたい」

  • 「Emotion使ってみたけど、なんかCSSが適用されないんだけど...」

上記の悩みにお答えします。

Emotion」はJavaScriptでCSSを記述するために作られたライブラリで、いわゆるCSS-in-JSのひとつです。

同じCSS-in-JSの中で、「styled-components」というものがあります。
Emotionstyled-componentsはよく比べられますよね。

Emotionを使うべきなのか、どうやって使えばいいのか悩んでいる方も多いはず。

そこで、この記事ではReactでEmotionを使う方法を解説します。

内容は以下です。

  • Emotionを使うメリット

  • Emotionの導入

  • 基本的な使い方

  • 応用的な使い方

  • styled-componentsみたいに使う

Emotionを使うメリット

主に以下の2つ。

  • タグが見分けやすい

  • styled-componentsの書き方もできる

タグが見分けやすい

Emotionの方がタグを見分けやすいです。
タグっていうのは、「div」とか「h1」とかのことですね。

styled-componentsだと、タグが見分けにくいと言われています。

サンプルのコードが以下です。

/* styled-componentsの場合 */

<Wrapper>
  <Title>RalaCode</Title>
  <SubTitle>Web開発で経験した試行錯誤を発信</SubTitle>
  <More href="/">詳しく見る</More>
</Wrapper>

一部省略してますが、上記がstyled-componentsのコード。
styled-componentsでは「div」や「h1」などのタグを、「Wrapper」や「Title」という自作のタグに変換することになります。

これだとパッと見、どれが「div」なのか「h1」なのかわかりにくいですよね。

Emotionの場合だと、以下です。

/* Emotionの場合 */

<div css={wrapper}>
  <h1 css={title}>RalaCode</h1>
  <p css={subTitle}>Web開発で経験した試行錯誤を発信</p>
  <a href="#" css={more}>詳しく見る</a>
</div>

Emotionでは「css」という属性を使います。
これなら、タグを見分けやすいですよね。

styled-componentsの書き方もできる

Emotionはstyled-componentsより後に開発されたものです。
実は、Emotionを導入すればstyled-componentsの書き方もできます。

そのやり方は後ほど解説します。

Emotionの環境さえあれば、Emotionもstyled-componentsも使えます。
万能ですよね。

Emotionの導入

一応、公式サイトにもEmotionの導入方法が解説されています。
リンクは以下です。

>> Emotionの公式サイトへ

公式サイトは英語なので、読むのが少し面倒かもです。
ここでは日本語でわかりやすく解説します。

まず、Reactプロジェクトを作ります。

$ npx create-react-app emotion-sample

Typescriptを使う場合は、以下です。

$ npx create-react-app emotion-sample --template typescript

プロジェクトのフォルダに移動して、開発サーバーが起動できるか確認しておきましょう。

$ cd emotion-sample
$ npm start

確認できたら、いったん開発サーバーは終了させておきます。
Windowsなら「Ctrl + "c"」、Macなら「control + "c"」です。

では、Emotionを導入します。

$ npm install @emotion/react

これで、Emotionの導入は完了です。
簡単ですね。

Emotionの基本的な使い方

では、実際にEmotionを使ってみます。

コードの書き方

App.jsを以下のように記述してください。

/* App.js */

import { css } from "@emotion/react";

function App() {
  return (
    <h1
      css={css`
        color: red;
      `}
    >
      Hello, world!
    </h1>
  );
}

export default App;

Hello, world!」という文字を表示してみました。
さらに、Emotionを使って「Hello, world!」の文字を赤色にするように設定しました。

これで、開発サーバーを起動してみましょう。

...ちゃんと表示されたでしょうか。

多分、「Hello, world!」の文字が黒色になっていませんか?
文字色を赤色に設定したはずなのに、変わっていませんよね?

JSX pragmaを設定する

実は、Emotionを使う場合は「ある設定」をしないといけません。
設定といっても、1行コードを追加するだけです。

では、App.jsに以下のような感じでコードを追加してください。

/* App.js */

/** @jsxImportSource @emotion/react */
import { css } from "@emotion/react";

function App() {
  return (
    <h1
      css={css`
        color: red;
      `}
    >
      Hello, world!
    </h1>
  );
}

export default App;

一番上の行に、以下のコードを追加しました。

/** @jsxImportSource @emotion/react */

JSX pragma」と呼ばれる記述です。

これでもう一度、「Hello, world!」の文字を確認してみてください。
赤色に変わっているはずです。

Emotionを使うコンポーネントでは、「JSX pragma」を書かないといけません。

Typescriptの場合は?

Typescriptの場合も「JSX pragma」を書いてください。
やることは他にありません。

ネットの情報を見ていると、「tsconfig.jsonに記述を加えましょう」みたいな説明があったりします。

具体的には、以下のような記述です。

/* tsconfig.json */
{
  "compilerOptions": {
    ......,
    "jsxImportSource": "@emotion/react"
  }
}

「"jsxImportSource": "@emotion/react"」という記述ですね。

確かにこれを書けば、Typescript上で「css」というプロパティに型定義が通るようにはなります。
ですが、結局Emotionは動きません

TypescriptでEmotionを使う場合も、JSX pragmaを書かないといけません。
tsconfig.jsonは触る必要ありません。

「じゃあ、tsconfig.jsonに記述を加えるのはどういうときなの?」
って感じですよね。

例えば「NextJS + TypescriptでEmotionを使うとき」です。

NextJSであればJSX pragmaを書かなくてもEmotionが使える設定ができます。
しかし、「Emotionは使えるけどTypescriptで型エラーが出る」という状態になります。

その型エラーを防ぐために、tsconfig.jsonをいじらないといけないわけです。

なんかややこしいですよね。
いったんまとめます。

create-react-appで作ったReactプロジェクトでEmotionを使う場合は、JSX pragmaを書きましょう。
Typescriptの場合もJSX pragmaを書きましょう。
tsconfig.jsonは触らないでいいです。

Emotionの応用的な使い方

いくつかご紹介します。

コードをまとめる

今のApp.jsを見てみると、「Hello, world!」を表示するだけなのにコードがごちゃついてますよね。
まとめた書き方をするとわかりやすくなります。

/* App.js */

/** @jsxImportSource @emotion/react */
import { css } from "@emotion/react";

const hello = css`
  color: red;
`

function App() {
  return (
    <h1 css={hello}>Hello, world!</h1>
  );
}

export default App;

hello」という定数にスタイルをまとめました。

スタイルを結合する

スタイルを複数定義して、結合することができます。

/* App.js */

/** @jsxImportSource @emotion/react */
import { css } from "@emotion/react";

/* ↓これ追加 */
const largeFont = css`
  font-size: 54px;

  @media (min-width: 768px) {
    font-size: 72px;
  }
`

const hello = css`
  color: red;
`

function App() {
  return (
    // largeFontを追加↓
    <h1 css={[hello, largeFont]}>Hello, world!</h1>
  );
}

export default App;

largeFont」という新たなスタイルを定義して、結合してみました。
結合する場合は「css={[hello, largeFont]}のように、配列形式になるので注意です。

スタイルの中ではメディアクエリも使っています。

これで「Hello, world!」という文字が大きくなったと思います。

また、スタイル自体をまとめることもできます。

/* App.js */

/** @jsxImportSource @emotion/react */
import { css } from "@emotion/react";

const largeFont = css`
  font-size: 54px;

  @media (min-width: 768px) {
    font-size: 72px;
  }
`

const hello = css`
  /* ↓これ追加 */
  ${largeFont}
  color: red;
`

function App() {
  return (
    // helloのみでOK↓
    <h1 css={hello}>Hello, world!</h1>
  );
}

export default App;

「largeFont」というスタイルを「hello」の中にまとめました。
「hello」というスタイルを適用するだけでよくなります。

「Hello, world!」の文字は、赤色で大きいままのはず。

グローバルスタイルを設定する

例えば、bodyタグにCSSを適用させたいときありますよね?

Emotionなら、それも簡単にできます。

App.jsを書き換えてみましょう。

/* App.js */

/** @jsxImportSource @emotion/react */
/* 「Global」をimportする↓ */
import { css, Global } from "@emotion/react";

const largeFont = css`
  ... 略...
`

const hello = css`
  ... 略 ...
`

function App() {
  return (
    <>
      {/* ↓「Global」を使ってbodyタグにスタイルを適用 */}
      <Global
        styles={css`
          body {
            margin: 0;
            font-family: -apple-system, BlinkMacSystemFont,
            "Segoe UI",Helvetica, Arial, sans-serif;
          }
        `}
      />
      <h1 css={hello}>Hello, world!</h1>
    </>
  );
}

export default App;

まず、「Global」を@emotion/reactからimportします。
そして、「Global」でbodyタグにCSSを適用させています。

以下のように、グローバルスタイルをまとめてもOK。

/* App.js */

/** @jsxImportSource @emotion/react */
import { css, Global } from "@emotion/react";

const largeFont = css`
  ... 略...
`

const hello = css`
  ... 略 ...
`

/* ↓グローバルスタイルを定義する */
const globalStyle = css`
  body {
    margin: 0;
    font-family: -apple-system, BlinkMacSystemFont,
    "Segoe UI",Helvetica, Arial, sans-serif;
  }
`

function App() {
  return (
    <>
      {/* ↓「styles」の中身は「globalStyle」のみでOK */}
      <Global styles={globalStyle} />
      <h1 css={hello}>Hello, world!</h1>
    </>
  );
}

export default App;

これで、コードがすっきりしますね。

また、「Global」はApp.jsだけでなく、どのコンポーネントで使っても大丈夫です。

styled-componentsみたいに使う

Emotionを導入すれば、styled-componentsの書き方もできます。
そのためには、「@emotion/styled」というパッケージを追加でインストールします。

$ npm install @emotion/styled

では、App.jsを以下のようにごっそり書き換えてみます。

/* App.js */

import styled from "@emotion/styled";

const Hello = styled.h1`
  color: red;
`

function App() {
  return (
    <Hello>Hello, world!</Hello>
  );
}

export default App;

これで、「Hello, world!」が赤文字で表示されるはずです。

「@emotion/styled」でCSSを適用する場合は、「JSX pragma」は書かなくていいです。

ところで、

なんでわざわざstyled-componentsの書き方する必要があるの?

って思いませんでしたか?

styled-componentsのいいところは、「動的にCSSを変化させられること」です。

例えば、以下のようなことができます。

  • ある条件下では文字をにする

  • 別の条件下では文字をにする

App.jsを書き換えてみます。

/* App.js */

import styled from "@emotion/styled";

const Hello = styled.h1`
  /* ↓このように書き換えます */
  color: ${props => (props.blue ? "blue" : "red")};
`

function App() {
  return (
    <>
      <Hello>Hello, world!</Hello>
      {/* ↓これ追加 */}
      <Hello blue>Hello, world!</Hello>
    </>
  );
}

export default App;

「Hello, world!」を2つにしてみました。

片方には「blue」という条件をつけています。
blue」という条件があるときは、文字色を青にするようにCSSを設定しました。

もう少し複雑なこともできます。
例えば、「ボタンを押すと文字色が変わる」みたいな機能。

そのやり方は以下の記事で解説してますので、合わせてどうぞ。

【React】styled-componentsの使い方【具体例あり】
【React】styled-componentsの使い方【具体例あり】
記事を読む

まとめ

最後に記事をまとめます。

React開発でEmotionを使うメリットは以下です。

  • タグが見分けやすい

  • styled-componentsの書き方もできる

@emotion/react」を使う場合は、「JSX pragma」を使わないといけないのが少しだけ面倒ですかね。

さらに、「@emotion/styled」を使えばstyled-componentsの書き方もできます。

styled-componentsなら、動的にCSSを変化させられます。

状況に応じて柔軟に使い分けられるのが、Emotionのいいところですね。

というわけで記事は以上です。

この記事を共有

以下のボタンを押すとSNSが開きます

Copyright © 2023 RalaCode