🥰

最強のCSS-in-JS!Kaze Styleの紹介!

2022/10/03に公開約4,400字

最近出たばかりのCSSライブラリである「Kaze Style」を紹介をします。
まだstar数は1です(僕のみ)が、かなり良さそうなので使ってみたいと思います。

https://github.com/taishinaritomi/kaze-style

特徴

公式から引用します。

  • KazeStyle can choose when to extract css. (build time & run time)
  • Type-safe styles via csstype
  • Reuse styles using Atomic CSS
  • Can ignore specificity and merge styles
  • Consistent styling using "@kaze-style/themes" (under development)

要するに、「ビルド時にAtomicなCSS生成できて、型安全で、しかもクラス名のマージもできちゃうライブラリだぜ!」ってことです。
また、公式からthemeなどが提供される予定で、tailwind cssのような一貫したスタイリングができるようになるようです。(執筆時点では@kaze-style/themesが公開されている)

詳しく見ていく

使い方

まずはサンプルを眺めてみます。

import { createStyle } from '@kaze-style/react';

const classes = createStyle({
  button: {
    color: 'red',
  },
});

const Component = () => {
  return <button className={classes.button}>button</button>;
};

クラス名のマージをする場合は

// Button.tsx
import { createStyle, mergeStyle } from '@kaze-style/react';

const classes = createStyle({
  button: {
    color: 'red',
  },
});

export const Button: FC<ComponentProps<'button'>> = (props) => {
  return (
    <button
      {...props}
      className={mergeStyle(classes.button, props.className)}
    />
  )
};

// pages/index.tsx
const classes = createStyle({
  button: {
    margin: '100px',
  },
});

const Home: NextPage = () => {
  return (
    <div>
      <Button className={classes.button}>Button</Button>
    </div>
  );
};

export default Home;

createStyleでスタイルを定義して、マージをする場合はスタイルを受け取る側のコンポーネントでmergeStyleを使います。
分かりやすく、かなりとっつきやすいAPIだと思います。

グローバルスタイル

リセットcssのように、スタイルをグローバルに効かせたい場合もあると思います。
そういう時はcreateGlobalStyleを使います。
また執筆時点では@kaze-style/themesというパッケージが提供されていて、resetStyleを使えば簡単にリセットcssを適用できます。
なお、この@kaze-style/themesは今後名前が変わる可能性もあるようです。
使用する際はリポジトリを見るなりして、気を付けて使用してください。

import { createGlobalStyle } from '@kaze-style/react';
import { resetStyle } from '@kaze-style/themes';
import type { AppProps } from 'next/app';

createGlobalStyle(resetStyle);

const App = ({ Component, pageProps }: AppProps) => {
  return (
    <div>
      <Component {...pageProps} />
    </div>
  );
};
export default App;

レスポンシブ

const classes = createStyle({
  button: {
    // 省略
    "@media screen and (max-width: 767px)": {
      color: "red",
    },
  },
});

theme

export const theme = {
  colors: {
    'blue': '#1fb6ff',
    'purple': '#7e5bef',
    'pink': '#ff49db',
    'orange': '#ff7849',
    'green': '#13ce66',
    'yellow': '#ffc82c',
    'gray-dark': '#273444',
    'gray': '#8492a6',
    'gray-light': '#d3dce6',
  },
  screen: {
    xs: '@media (max-width: 384px)',
    sm: '@media (max-width: 512px)',
    md: '@media (max-width: 768px)',
    lg: '@media (max-width: 1024px)',
  },
} as const;

上記のように、ただオブジェクトとして定義して

const classes = createStyle({
  button: {
    [theme.screen.xs]: {
      color: theme.colors.green,
    },
  },
});

とするだけです。

静的生成(Next.jsの場合)

// next.config.js
import { withKazeStyle } from '@kaze-style/next-plugin';

/** @type {import('next').NextConfig} */
const nextConfig = {};

export default withKazeStyle(nextConfig);

このようにするだけでビルド時にcssを生成する機能が使えるみたいです。
簡単すぎないか...?

パフォーマンス

Kaze Styleの場合

Emotionの場合

Stitchesの場合

@next/bundle-analyzerで確認してみた

びっくりするぐらいバンドルサイズが小さいですね。最後の画像なんて小さすぎて読めなくて、本当に正しいのか疑ったレベルです笑(黒い丸で印をつけておきました)
しかもAtomic CSSで静的生成できるので、今あるCSS-in-JSライブラリの中でもトップクラスのパフォーマンスと言っても過言ではないのではないでしょうか?

使ってみた感想

かなり直感的に書けたので体験はかなり良かったです。

tailwind cssはクラスのマージに一手間かかったり、クラス名覚える必要があったり、そもそもHTMLが汚くなったりで、時々炎上したりします(たいていのクラス名はすぐに覚えられるとはいえ、たまに覚えずらいのもありますよね...)。
最近だと@uhyo_さんの記事が話題になりましたよね。

僕自身はtailwind結構好きで使っていますが、tailwindが最適だと思っているから使っているのではなく、現状それ以上の最適解を知らないから使っていたという側面もあります[1]

Kaze Styleはバンドルサイズも小さく、CSS Modulesのようにコンポーネントとスタイルを分離することなく書くことができ、かつ型安全なので求めていたものがだいたい入った最強のCSSライブラリかもしれない!と思いました。

tailwindからの移行先、CSS-in-JSの選定の一つの選択肢としていかがでしょうか!

おまけ

  • Kaze Styleの由来はそのまま「風」です。実はtailwind(追い風)を意識して作られたらしいです。
  • Kaze Styleをベタ褒めしましたが、僕は作者ではありません。
  • どなたかつよつよエンジニアの方はコントリビュートしてあげてください(僕には難しすぎる)
脚注
  1. 手軽さ、バンドルサイズ、importしなくて良い、htmlとcssを行き来しなくて良いなど好きなところもたくさんあります。 ↩︎

GitHubで編集を提案

Discussion

ログインするとコメントできます