「React開発でEmotionを導入したい」
「styled-componentsより使える?」
「TypescriptでEmotionを使いたい」
「Emotion使ってみたけど、なんかCSSが適用されないんだけど...」
上記の悩みにお答えします。
「Emotion」はJavaScriptでCSSを記述するために 作られたライブラリで、いわゆるCSS-in-JSのひとつです。
同じCSS-in-JSの中で、「styled-components」というものがあります。
Emotionとstyled-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の導入方法が解説されています。
リンクは以下です。
公式サイトは英語なので、読むのが少し面倒かもです。
ここでは日本語でわかりやすく解説します。
まず、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開発でEmotionを使うメリットは以下です。
タグが見分けやすい
styled-componentsの書き方もできる
「@emotion/react」を使う場合は、「JSX pragma」を使わないといけないのが少しだけ面倒ですかね。
さらに、「@emotion/styled」を使えばstyled-componentsの書き方もできます。
styled-componentsなら、動的にCSSを変化させられます。
状況に応じて柔軟に使い分けられるのが、Emotionのいいところですね。
というわけで記事は以上です。