🙌

Zero-Runtime CSSのLinariaを触ってみた

2023/12/28に公開

こんにちは、spacemarketのフロントエンドエンジニアの8zkです。

みなさん、Linariaを知っていますか?
LinariaはZero-Runtime CSSの一種です。
今回は個人的に気になったCSSライブラリ、Linariaを触ってみたのでその感想などを書いていきたいと思います。

GitHubはこちら。
https://github.com/callstack/linaria
現時点でstar数は1万を超えていますね。

Linariaの特徴

こちらがLinariaの特徴です。

* Write CSS in JS, but with zero runtime, CSS is extracted to CSS files during build
* Familiar CSS syntax with Sass like nesting
* Use dynamic prop based styles with the React bindings, uses CSS variables behind the scenes
* Easily find where the style was defined with CSS sourcemaps
* Lint your CSS in JS with stylelint
* Use JavaScript for logic, no CSS preprocessor needed
* Optionally use any CSS preprocessor such as Sass or PostCSS
* Supports atomic styles with @linaria/atomic

要約すると以下のような感じ。

* CSS in JSとして書けますが、ランタイムでは実行されません。 CSSはCSSファイルとしてビルド時に生成されます。
* Sassのようなネストを用いたおなじみのCSSのsyntaxを使うことができます。
* Reactのルールに則った動的なPropsをベースとしたスタイリングができ、シーンに応じてCSS変数を利用できます。
* CSSソースマップで定義されたstyleを簡単に発見できます。
* stylelintを用いてあなたのCSS in JSをlintできます。
* ロジックにJavaScriptを使え、CSS preprocessor(SassやPostCSS)を必要としません。(オプショナルだけど、SassやPostCSSを使えるよ)
* @linaria/atomicを使えばatomic styleのCSSを書けます。

この中で重要だと感じた部分はこちら。

CSS in JSとして書けますが、ランタイムでは実行されません。 CSSはCSSファイルとしてビルド時に抽出されます。

CSS in JSはフロントエンドエンジニア(少なくとも私)にとって書き心地が良いものです。なぜなら多くの場合はtsxファイルを編集しています。そのファイルに直接CSSを書くことが出来るためファイルをたくさん開いて編集する必要がなく楽です。

ただその性質上CSS in JSの多くはランタイムで実行されるため、アプリケーションのパフォーマンスに影響が出ます。
昨今ではNext.jsのSSGなどによってアプリケーションのビルド時にAPI呼び出しを行いHTMLを生成する方式が取られます。これは認証を必要としない画面においては優れたアプローチであり、ビルド時にAPI呼び出しまで済ませておけばユーザーはより早く画面が表示されます。

このアプローチに近いのがLinariaのようなZero-Runtime CSSです。こちらもビルド時にCSSがCSSファイルとして生成され、ランタイムでLinariaは実行されないためユーザーにとっては早く画面が表示されます。
(ちなみにCSS in JSとは別ですが、Tailwind CSSのようなユーティリティクラスを利用したCSS libraryもあります。こちらはタグにクラス名が大量に並ぶので個人的にはちょっと見辛いなぁと感じます)

では早速触っていきましょう。

書き方

import { styled } from '@linaria/react';

// Create a styled component
const Thing = styled.div`
  color: black;

  &::after {
    /* .thing::after */
    content: '🌟';
  }

  h3 {
    /* .thing h3 */
    color: tomato;
  }

  .code {
    /* .thing .code */
    color: #555;
  }

  & + & {
    /* .thing + .thing */
    background: yellow;
  }

  &.bordered {
    /* .thing.bordered */
    border: 1px solid black;
  }

  .parent & {
    /* .parent .thing */
    color: blue;
  }
  
  @media (min-width: 768px) {
    color: blue;
  }
  
  @keyframes spin {
    from {
      transform: rotate(0deg);
    }

    to {
      transform: rotate(360deg);
    }
  }
`;

function Heading() {
  // Use the styled component
  return <Thing>This is a title</Thing>;
}

基本的な書き方はstyled-componentsと同じです。
メディアクエリや擬似クラスもLinariaではサポートしています。

またこの書き方以外にも

import { css } from '@linaria/core';

// Create a class name
const title = css`
  font-size: 24px;
  font-weight: bold;
`;

function Heading() {
  // Pass it to a component
  return <h1 className={title}>This is a title</h1>;
}

のようなclassName styleな書き方もできます。

よくあるstyleの上書きをしたいケースでは

const Button = styled.button`
  font-size: 14px;
  background-color: tomato;
  padding: 8px;
  box-shadow: 0 0.5px 0.3px rgba(0, 0, 0, 0.1);
`;

const LargeButton = styled(Button)`
  font-size: 18px;
  padding: 16px;
`;

のようにstyled-componentsと全く同じような記法に書くことができます。

また、styleやclassNameをreact componentに渡すことでreact componentのstyleも上書きすることが出来ます。これもstyled-componentsと同じような振る舞いですね。

function CoolComponent({ className, style, ...rest }) {
  return (
    <div className={className} style={style}>
      {...}
    </div>
  );
}

const StyledCoolComponent = styled(CoolComponent)`
  background-color: tomato;
`;

Global styleは以下のように書くことが出来ます。

export const globals = css`
  :global() {
    html {
      box-sizing: border-box;
    }

    *,
    *:before,
    *:after {
      box-sizing: inherit;
    }

    @font-face {
      font-family: 'MaterialIcons';
      src: url(../assets/fonts/MaterialIcons.ttf) format('truetype');
    }
  }
`;

動的なスタイルの変更もできます。

const Content = styled.div`
  height: ${props => props.size}px;
  width: ${props => props.size}px;
`;

function Component() {
  return (
    <Content size={56} />
  )
}

以上が基本的な書き方になります。

Linariaの魅力

  • エクスポートされない限りファイル内の未使用のスタイルを自動的に削除する
  • 自動でベンダープレフィックスをつけてくれる
  • 他のCSS in JSと比べて、スタイルは別のCSSファイルに生成されるため、CSSとJavaScriptはブラウザーで並行してダウンロードして解析でき、読み込み時間を短縮できる

まとめ

今回はZero-Runtime CSSのLinariaを触ってみました。
styled-componentsを書いていた私にとっては、おなじみの記法が随所に見られとても書きやすいものでした。
また、ランタイムで実行されないためパフォーマンスがよく、開発者やユーザーにとっては喜ばしいものだと感じました。

最後に

スペースマーケットでは一緒に働く仲間を募集しています!
少しでも興味を持ってくださったら、ぜひご連絡ください!

https://herp.careers/v1/spmhr/oZ-mn0UYmzXj

https://herp.careers/v1/spmhr/kXsNqAxjlbaI

https://herp.careers/v1/spmhr/qZ-3RxrPtDgM

https://herp.careers/v1/spmhr/m2LlDFRg7Ck0

https://herp.careers/v1/spmhr/SgOXIYU-ovNw

スペースマーケット Engineer Blog

Discussion