GatsbyJS CSSを指定する(CSS-in-JS Emotion)

2019-06-05

CSS-in-JSライブラリ[Emotion]

EmotionはCSS-in-JSライブラリ(CSSを記述するために設計されたライブラリ)の1つで、元々あったstyled-componentsなどに影響されて作成されたライブラリです(とくにGatsby用とうわけではない)。

Emotionのインストール

  • Gatsbyプロジェクトディレクトリでインストールを実施
npm install --save gatsby-plugin-emotion @emotion/core @emotion/styled
  • gatsby-config.jsにプラグインを追加 pluginsにgatsby-plugin-emotionを追加する
module.exports = {
    plugins: [
        `gatsby-plugin-emotion`//この部分を追記する
    ],
}

EmotionでCSSを記述する方法

CSSを記述する方法はCSSpropとStyledComponentsの2パターンあります。

CSSpropで記述する

Emotionを利用するときにメインとなる方法、要素の cssプロパティにCSSの内容を指定します。
cssプロパティにはオブジェクト型、文字列型が指定できます。

  1. まずEmotionをimportする
    [@emotion/core]からjsxとcssをインポートし、JSX Pragma [/** @jsx jsx */]を記述します。 (cssは文字列型でCSSを指定するときに必要)
/** @jsx jsx */
import { jsx, css  } from '@emotion/core'
  1. 要素にCSSを指定する
    要素のcssプロパティにCSSの内容を記述したオブジェクトを指定します。
<div
css={{
    backgroundColor: 'green',
    color: 'white'
}}
>
  1. サンプルページの作成
    CSSの内容を変数で定義するように変更し、文字列型の場合のCSSも追加します。
import React from "react"
/** @jsx jsx */
import { jsx, css  } from '@emotion/core'

// オブジェクト型のCSS定義(キャメルケースで記述する)
const obj = {
    backgroundColor: 'green',
    color: 'white'
}

// 文字列型のCSS定義
const str = `
    background-color: blue;
    color: white;
`;

export default () => (
    <div>
        <div css={obj}>
        オブジェクト型で指定
        </div>
        <div css={css`${str}`}>
        文字列型で指定
        </div>
    </div>
)

ブラウザで確認すると、それぞれのCSSが適用されていることが確認できます。 cssprop_1.png

CSSの上書き

CSSを指定したコンポーネントを、別のコンポーネントで利用するときにCSSを上書きできます。
上書きという表現が使われていますが、別のコンポーネントはCSSが後から設定するので優先されるという感じです。

例として以下の2つのコンポーネントを作成します。

  • NormalP:pタグにbackgroundColor、fontSize、colorを指定する
  • StyleP:NormalPコンポーネントにfontSize、colorを指定する

propsにclassNameが渡されてくるので、classプロパティの設定をするためコンポーネントに展開します。

import React from "react"
/** @jsx jsx */
import { jsx  } from '@emotion/core'

// NormalPコンポーネントの定義
const NormalP = props =>  (
    <p
    css={{
        backgroundColor:'moccasin',
        fontSize: 12,
        color: 'maroon',
    }}
    {...props}//propsにclassNameが送られてくる、htmlのclassプロパティ用に展開
    />
)

// StylePコンポーネントの定義
const StyleP = props => (
    <NormalP
    css={{
        fontSize: 30,
        color: 'springgreen'
    }}
    {...props}
    />
)

export default () => (
    <div>
        <NormalP>
        NormalPの内容
        </NormalP>
        <StyleP>
        StylePの内容
        </StyleP>
    </div>
)

ブラウザで確認すると、StylePコンポーネントのCSSにはStyleP定義時に指定したfontSize、colorで上書きされていますが、backgroundColorはNormalPのCSSがそのまま使われています。 cssprop_2.png

仕組みとしては以下の様に処理を行っているようでした。

  1. まずStylePコンポーネントの処理に入り、propsにclassNameが設定されNormalPコンポーネントを呼び出す。
  2. NormalPコンポーネントが処理されpタグを作成する、このpタグにNormalPのCSSを設定し、propsを展開するのでclassNameがclassプロパティとして出力される。
  3. StylePがpタグにCSSを設定する。
  4. HTMLとして出力。

cssprop_5.png

HTMLソースを確認すると、StylePコンポーネントが出力したpタグにNormalPの 「backgroundColor:'moccasin'」「fontSize: 12」が取り消されているのが確認できます。 cssprop_4.png

propsをすべて展開したくない場合は、classNameプロパティとprops.childrenを自分で設定しても同じ結果になります。

// NormalPコンポーネントの定義
const NormalP = props => (
    <p
    css={{
        backgroundColor:'moccasin',
        fontSize: 12,
        color: 'maroon',
    }}
    className={props.className}{/* classNameを自分で設定*/}
    >
    {props.children}{/* 子要素の設定*/}
    </p>
)

StyledComponentsで記述する

StyledComponentsの記述は他のCSSinJSのstyled-componentsやglamorousに似ており、 コンポーネント定義時にCSSも定義する方法となります

  1. StyledComponentsで記述するにはstyledのインポートをインポートします。
import styled from '@emotion/styled'
  1. コンポーネント作成時にstyledを使用し、要素とCSSを指定します。
// DIV_TESTコンポーネントはdivタグでcolor: red
const DIV_TEST = styled.div`
    color: red;
`
  1. サンプルページとしてCSSpropの例で作成したNormalPコンポーネントを作成してみます。
import React from "react"
import { css } from "@emotion/core"
import styled from "@emotion/styled"

// NormalPコンポーネントの定義
const NormalP = styled.p`
    background-color:moccasin;
    font-size: 12px;
    color: maroon;
`

export default () => (
    <div>
        <NormalP>
        NormalPの内容
        </NormalP>
    </div>
)

同じ内容が表示されます。

StyledComponents_1.png

CSSの上書き

StyledComponentsで別のコンポーネントのCSSを上書きする場合には、styled(コンポーネント名)と記述します。
CSSpropと同様に以下の2つのコンポーネントを作成します。

  • NormalP:pタグにbackgroundColor、fontSize、colorを指定する
  • StyleP:NormalPコンポーネントにfontSize、colorを指定する
import React from "react"
import { css } from "@emotion/core"
import styled from "@emotion/styled"

// NormalPコンポーネントの定義
const NormalP = styled.p`
    background-color:moccasin;
    font-size: 12px;
    color: maroon;
`

// StylePコンポーネントの定義(NormalPのCSSの内容を取得する)
const StyleP = styled(NormalP)`
    font-size: 30px;
    color: springgreen;
`

export default () => (
    <div>
        <NormalP>
        NormalPの内容
        </NormalP>
        <StyleP>
        StylePの内容
        </StyleP>
    </div>
)

ブラウザの表示結果や、HTMLソースが同じように出力されていることが確認できます。 StyledComponents_2.png

参考

Emotion公式サイト

■同じタグの記事(最新5件)
GatsbyJS FaunaDBからデータを取得する
GatsbyJS 検索機能を実装する(JsSearchを利用)
GatsbyJS PostgreSQLの内容を取得する
GatsbyJS rehypeReactでマークダウンの内容を変更する
GatsbyJS マークダウンにコンポーネントを表示する
■同じタグの記事を見る