emotion logo

CSSまわりをTailwindからEmotionに乗り換える

2022年10月22日

最後にブログに大きな改修を加えたのは2021年4月で、1年半ほど何も手を加えず記事だけ書き続けていました。色々直したい所も出てきたので、ここ最近はあちこちに手を入れていますが、その中でも大きな所としてスタイルシートまわりを全面的に書き直しました。

CSS-in-JS

元々使っていたTailwind CSSは、CSSの大きな塊をPostCSSを使ってビルド時に削るという工程が発生しておりそのためのセットアップがやや大げさな印象でした。作業量もタイプ量はともかく実際にスタイルを考えながら付けていく過程自体は生のCSSとあまり変わらないので、直接CSSを書くことにしました。

さて生のCSSを書いてそれをimportで取り込んでもよいのですが、もう少しモダンな書き方をしたいということでGatsbyのドキュメントを漁ったところ、コンポーネントの中にCSSを書く方法としてGatsbyでサポートしているものは主にStyled ComponentsというものとEmotionというものがあるようでした。調べてみるとEmotionが後発で、Styled Componentsの書き方も取り入れているということでEmotionを採用することにしました。

実は他のものも試していました

実はEmotionを採用すると決める前に、他のCSS-in-JSライブラリも試しており、Tailwindとの互換性を謳うTwindというものをほんの一瞬だけ採用していました。実際にTailwindからの移行はかなり簡単で、よりJavaScript的な書き方も部分的に採用できるという素敵なライブラリなのですが、実際にデプロイしてみるとパフォーマンスが激しく悪化していました。

2210 0055 firefox

これはCSS-in-JSの特性として、JavaScriptによって後付けで各要素にスタイルを付けるようになっているのですが、これにより読み込みからスタイルの適用までにかなりの時間差が生じていたのと、マージンなども後から適用されることで大きなレイアウトのズレが生じる(これはFOUCと呼ばれているようです)ことがLighthouseの評価を下げる要因になっていたようです。またこれにより、JavaScriptがオフになっている場合スタイルが全く適用されないページが出てきてしまいます。Gatsbyが正式に対応しているCSS-in-JSライブラリでは、ビルド時にページを解析して自動的にページ内に適宜生のCSSも埋め込むようになっており、パフォーマンスには影響が出ないようになっているようなのです。

実際に使ってみる

実際にこのブログで使っているコンポーネントのひとつがまるまるお手本のようなものになっているので、そのまま出してみます。

import * as React from "react"
import { Link } from "gatsby"
import styled from "@emotion/styled"
import { css } from "@emotion/react"

const Container = styled.header({
    margin: '0 auto',
    maxWidth: '56rem',
    padding: '2.5rem 1rem',
    '@media screen and (min-width: 480px)': {
        padding: '5rem 1rem',
    },
})

const Title = css({
    fontSize: "3.5rem",
    lineHeight: 1,
    fontWeight: 900,
    letterSpacing: "-0.05em",
    color: "#efb864",
    textDecoration: "none",
})

const Header = () => {
    return (
        <Container>
            <h1>
                <Link to="/" css={ Title }>Lon<br/>Sagisawa</Link>
            </h1>
        </Container>
    )
}

export default Header

divなどの要素は「スタイルの付いたdiv」として空っぽのコンポーネントを作って呼び出す形になり、Linkといった既存コンポーネントにはcssプロパティでスタイルを付けることができる、というものになっています。スタイルはエディタの補完や型を使うためにオブジェクトスタイルという形式で書いており素のCSSとは文法が異なりますが、テンプレートリテラルで書くことで素のCSSと同じ書き方ができるようになっています。

また忘れてはいけないこととして、EmotionはTailwindのように勝手にリセットCSSを仕込んでくれたりはしないので、その辺りは自分でやらなければいけません。Gatsbyのチュートリアルの通りにサイトを構築しているのであれば、「汎用レイアウト用コンポーネント」の類を用意していると思うので、そこにリセットcssの類を仕込むのがよいでしょう。今回はemotion-sanitizeを使いましたが、実際に使ってみるとどうも自分にはsanitize.cssよりもnormalize.cssのほうが性に合っていそうなことがわかりました。

2210 0054 msedge

Gatsby用のEmotionプラグインの設定も行い、スタイルが各ページに埋め込まれるようになりました。Lighthouseを計測するとTailwindを使っていた頃と同等のパフォーマンス評価に戻っていたので、これでひと安心。