🎴

UnoCSS を知る、まずは経緯から

2024/08/15に公開
1

👋 はじめに

ナイトウ(@engineer_naito)と申します。
今回は CSS フレームワーク Atomic CSS エンジンである UnoCSS について紹介したいと思います。

🧐 想定読者

Tailwind CSS などの CSS フレームワークを利用したことのある開発者であればスラスラ読めると思いますが、初学者の方であっても問題なく読めると思います。
(なぜならばぼく自身が CSS フレームワークを使ったモダンフロントエンド開発の経験がないからです 🙋‍♂️)

🗾 UnoCSS と日本

UnoCSS は軽量かつ柔軟な Atomic CSS エンジンであり、現在最も注目を集めている CSS ツールの一つです。

https://risingstars.js.org/2022/ja#section-css-in-js

2022 JavaScript Rising Stars CSS in JS 部門1位

https://risingstars.js.org/2023/ja#section-css-in-js

https://2023.stateofcss.com/ja-JP/css-frameworks/

State of CSS CSS フレームワーク部門満足度ランキング2位

人気調査サイトの結果によると、ここ 2, 3 年で確かに人気や知名度が上昇しています。
しかし、日本ではどうでしょうか?
Zenn で「UnoCSS」と検索してみます。

Zenn での UnoCSS 検索結果 2024.08.05 時点

4 記事、4 スクラップです 😇
(2024.08.05 時点)

一方 Tailwind CSS の Zenn 記事

Zenn での Tailwind CSS 検索結果 2024.08.05 時点

769 記事
33 冊
152 スクラップ
🙄

UnoCSS は世界的には人気を集めていますが、日本ではまだ情報が足りてないように感じられました。

設計思想に共感したり、特徴を気に入ってくれたりして、UnoCSS を好きになる方が増えることを願います。
CSS フレームワークの選択肢の一つになってほしいです。

🏛️ 背景

Atomic CSS (エンジン)とはなんでしょうか。
UnoCSS はどのようにして生まれたのでしょうか。
Atomic CSS の考えを知り、UnoCSS の誕生の経緯や理由を知ることで、UnoCSS の設計思想や特徴を深く理解することができます。

⭐️ Anhony Fu 氏

UnoCSS の作者は Anthony Fu 氏です。

https://antfu.me/

Hey, I am Anthony Fu, a fanatical open sourceror.

Anthony Fu 氏は OSS に多大なる貢献をしている開発者であり、
(Vitest, Slidev, VueUse, Elk, Type Challenges)

Vue, Nuxt, Vite のコアチームメンバーでもあります。

UnoCSS の誕生した経緯が作者 Anthony Fu 氏のブログ記事 Reimagine Atomic CSS に記されています。

⚛️ Atomic CSS

Atomic CSS は Functional CSS, Utility First CSS とも呼ばれます。

John Polacek 氏の記事 Let’s Define Exactly What Atomic CSS is に以下の記述があります。

Atomic CSS is the approach to CSS architecture that favors small, single-purpose classes with names based on visual function.

Atomic CSS とは、視覚的な機能に基づいて命名された単一の目的を持つ小さなクラスを支持する(好む) CSS アーキテクチャのアプローチである、ということです。

のような ユーティリティファースト CSS フレームワークがあります。
おおよそ以下のような CSS のコレクションになっています。

.m-0 {
  margin: 0;
}
.text-red {
  color: red;
}
/* ... */

🌅 UnoCSS 誕生の経緯と背景

作者である Anthony Fu 氏は Vite の作者であり、主に Vite を利用して開発を行なっています。
Atomic CSS を活用したスピーディな開発を好んでおり、Vite のスターターテンプレート Vitesse 開発の UI フレームワークとして、Tailwind CSS を採用していました。

Vite が Webpack などに比べて爆速であるのに対し、Tailwind CSS は数 MB のユーティリティ CSS を生成するため、起動時や Vite の HMR で遅くなってしまっていました。
当初は Atomic CSS を利用する際の代償(trade-off)だと考えていましたが、Windi CSS に出会い、考えが変わります。

https://windicss.org/

Windi CSS は Tailwind CSS の代替としてフルスクラッチで作成されました。
Windi CSS の一番の特徴はオンデマンドな点です。
実際に用いたもののみ CSS が生成されるということです。
この特徴は Vite の思想にも合致していたため Tailwind CSS よりもずっと早くなると考えます。
Vite プラグインを開発したところ、Tailwind CSS に比べて 20~100 倍の速度が出るようになったとのことです。

https://x.com/antfu7/status/1361398324587163648

Windi CSS の開発を行っていた Anthony Fu 氏ですが、Tailwind CSS と互換のあるカスタムユーティリティの定義方法に疑問を抱きました。
Tailwind CSS の設計思想はオンデマンドなアプローチに合致しません。
そこで Anthony Fu 氏はオンデマンドなアプローチを念頭に置き、一から設計し直すことができるならどんな結果が得られるのかと考え始めました。
その考えをもとにいくつかの実験を行い、生まれたのが Atomic CSS エンジン UnoCSS です。

https://x.com/antfu7/status/1445368569550688256

📝 まとめ

UnoCSS は、Anthony Fu 氏が Tailwind CSS のパフォーマンス問題とカスタマイズの難しさを解決するために開発した、オンデマンドで動作する Atomic CSS エンジンです。
Windi CSS の影響を受け、より迅速柔軟なスタイル定義を可能にするために設計されました。

Atomic CSS は、視覚的な機能に基づいて命名された単一の目的を持つ小さなクラスを支持するアプローチであり、
効率的なスタイル管理と再利用性を重視しています。

このように、UnoCSS は既存の CSS フレームワークの課題を解決し、開発者にとってより使いやすく、高速な開発体験を提供するために誕生しました。

🔍 UnoCSS の特徴

UnoCSS の誕生背景を説明しました。
Tailwind CSS, Windi CSS にどのような課題があり、それを解決するために Anthony Fu 氏が UnoCSS を作成したことが理解できましたでしょうか?

そうして生まれた UnoCSS の特徴を紹介していきます。

UnoCSS 公式ドキュメントトップページ のスクショ

Instant On-demand Atomic CSS Engine

特徴 説明
Fully Customizable コアユーティリティなし、全ての機能はプリセットで提供
Instant パース、AST、スキャンなし。Windi CSS や Tailwind CSS JIT より 5 倍以上高速
Lightweight 依存関係ゼロでブラウザフレンドリー、約 6KB(最小化+ brotli 圧縮)
Rich Integrations Vite, Webpack, PostCSS, CLI, VS Code, EsLint などのファーストクラスサポート
Shortcuts ユーティリティの動的グループ化とエイリアス
Attributify Mode 属性内のグループユーティリティ
Pure CSS Icons アイコンを単なるクラスとして使用
Variant Groups グループユーティリティの共通プレフィックスの短縮系
CSS Directives @apply ディレクティブによる CSS の再利用
Compilation Mode ビルド時に複数クラスを 1 つに統合
Inspector インタラクティブなデバッグとインスペクト
CDN Runtime Build CDN インポート(1 行)による UnoCSS の利用

💡 UnoCSS 特徴まとめ

  1. 完全カスタマイズ可能で軽量:
    UnoCSS は依存関係がなく、最小化+ brotli 圧縮で約 6KB という非常に軽量な設計です。
    全ての機能はプリセットで提供され、コアユーティリティがないため、開発者は自分のプロジェクトに最適な設定を柔軟に構築できます。

  2. 瞬時に反映されるパフォーマンス:
    パースや AST、スキャンが不要で、Windi CSS や Tailwind CSS JIT よりも 5 倍以上の速度で動作します。
    これにより、リアルタイムの開発体験が向上し、効率的なスタイリングが可能です。

  3. 豊富な統合と使いやすさ:
    Vite、Webpack、PostCSS、CLI、VS Code、ESLint などのツールとシームレスに統合でき、開発環境を選ばずに利用できます。
    また、@applyディレクティブやショートカット機能、属性モードなどにより、直感的かつ効率的にスタイルを適用できるよう設計されています。

🌿 UnoCSS の基本的な使用方法

さて、UnoCSS の基本的な使い方を見ていきましょう。

🎨 独自ユーティリティの定義と使用

設定ファイルにルールとして記述できます。

uno.config.ts
import { defineConfig } from "unocss";

export default defineConfig({
  rules: [
    ["m-1", { margin: "1px" }],
  ],
});
<div class="m-1">Hello</div>
.m-1 {
  margin: 1px;
}


より柔軟(動的)なルールを設定するには正規表現と関数を用います。

uno.config.ts
import { defineConfig } from "unocss";

export default defineConfig({
  rules: [
    [/^m-([.\d]+)$/, ([, num]) => ({ margin: `${num}px` })],
  ],
});
<div class="m-1">Hello</div>
<div class="m-7.5">World</div>
.m-1 {
  margin: 1px;
}
.m-7.5 {
  margin: 7.5px;
}

🥤 「抽出(extracting)」

UnoCSS は、HTML や JavaScript/TypeScript のコードから使用されているクラスを自動的に「抽出(extracting)」し、必要なスタイルのみを生成します。
無駄な CSS が生成されるのを防ぎ、非常に軽量かつ効率的なスタイルシートを作成できます。

UnoCSS では複数のソースから「抽出」することができます。

  • ビルドツールパイプライン
  • ファイルシステム
  • インラインテキスト

🚰 ビルドツールパイプライン

ビルドツールパイプラインからの「抽出」は最も効率的かつ正確な方法です。
「抽出」対象のファイルはデフォルトでは、.jsx, .tsx, .vue, .md, .html, .svelte, .astro です。
デフォルトでは .js, .ts が対象外です。

.js, .ts を含めるには設定ファイルに記述します。

uno.config.ts
import { defineConfig } from "unocss";

export default defineConfig({
  content: {
    pipeline: {
      include: [
        // デフォルト
        /\.(vue|svelte|[jt]sx|mdx?|astro|elm|php|phtml|html)($|\?)/,
        // js/ts ファイル
        "src/**/*.{js,ts}",
      ],
      // exclude: [],
    },
  },
});

👀 ファイルシステム

ビルドツールのパイプラインにアクセスできない統合(PostCSS プラグインなど)を使用している場合や、
コードがパイプラインを通らないようなバックエンドフレームワークと統合している場合には、手動で「抽出」するファイルを指定することができます。

uno.config.ts
import { defineConfig } from "unocss";

export default defineConfig({
  content: {
    filesystem: [
      "src/**/*.php",
      "public/*.html",
    ],
  },
});

🔤 インラインテキスト

インラインテキストからも「抽出」することができます。

関数を用いて動的にテキストを渡すことができますが、ビルド時に一度だけ呼ばれることに注意が必要です。

uno.config.ts
import { defineConfig } from "unocss";

export default defineConfig({
  content: {
    inline: [
      "<div class="p-4 text-red">Some text</div>",
      async () => {
        const response = await fetch("https://example.com");
        return response.text();
      },
    ],
  },
});

🛠️ プリセット

いくつかのルールをプリセットとしてし抜き出して共有できます。

my-preset.ts
import type { Preset } from "unocss";

export const myPreset: Preset = {
  name: "my-preset",
  rules: [
    [/^m-([.\d]+)$/, ([_, num]) => ({ margin: `${num}px` })],
    [/^p-([.\d]+)$/, ([_, num]) => ({ padding: `${num}px` })],
  ],
  variants: [/* ... */],
  shortcuts: [/* ... */],
  // ...
};
uno.config.ts
import { defineConfig } from "unocss"
import { myPreset } from "./my-preset"

export default defineConfig({
  presets: [
    myPreset,
  ],
});

📌 公式プリセット

UnoCSS のコアユーティリティなしの「柔軟性」、「拡張性」を説明しました。
Tailwind CSS などのユーティリティファースト CSS フレームワークに馴染みのある方々はルールやプリセットの定義を億劫に感じるかもしれません。

安心してください。
そんな方々のために、UnoCSS では公式のプリセットが用意されています。
@unocss/preset-uno

  • Tailwind CSS
  • Windi CSS
  • Bootstrap
  • Tachyons

などのユーティリティファースト CSS フレームワークを含む共通のスーパーセットを提供しようと試みています。
慣れ親しんだクラス名やスタイルをそのまま使い続けることができるため、学習コストも最小限に抑えられるのではないでしょうか。

pnpm add -D @unocss/preset-uno
.ma4 {
  margin: 1rem; // Tachyons
}
.ml-3 {
  margin-left: 0.75rem; // Tailwind CSS
}
.ms-2 {
  margin-inline-start: 0.5rem; // Bootstrap
}
.mt-10px {
  margin-top: 10px; // Windi CSS
}

✅ 属性化モード

https://unocss.dev/presets/attributify#attributify-mode

Tailwind CSS を使用していると以下のようなボタンを実装することがあるでしょう。

<button
  class="bg-blue-400 hover:bg-blue-500 text-sm text-white font-mono font-light py-2 px-4 rounded border-2 border-blue-200 dark:bg-blue-500 dark:hover:bg-blue-600"
>
  Button
</button>

「属性化」(attributify)モードでは、以下のようになります。

<button
  bg="blue-400 hover:blue-500 dark:blue-500 dark:hover:blue-600"
  text="sm white"
  font="mono light"
  p="y-2 x-4"
  border="2 rounded blue-200"
>
  Button
</button>

ユーティリティを属性として指定できるだけでなく、text-sm text-whitetext="sm white" のように共通プレフィックスのユーティリティをまとめることができます。
(因数分解みたいですね 👀)

加えて、値なしの属性も使用できます。

<div m-2 rounded text-teal-400 />
⚠️ 属性名の衝突

属性モードの名前が要素やコンポーネントのプロパティとの競合を避けるために (UnoCSS の「属性化」モードであることを明示するために)、プレフィックスを追加することができます。

<a text="red">This conflicts with links' `text` prop</a>
<!-- to -->
<a uno-text="red">Text color to red</a>
presetAttributify({
  prefix: "uno-",
  prefixedOnly: true, // プレフィックスを強制できます
});

🕵️ インスペクタ

UnoCSS インスペクタを実際に使用したスクショ

Vite サーバでは UnoCSS インスペクタを利用できます。
localhost:5173/__unocss

インスペクタにより、生成された CSS ルールや各ファイルに適用されたクラスを確認できます。
また、現在の設定に基づいてユーティリティをテストするための REPL も提供されています。

💭 まとめ

UnoCSS は、

  • 柔軟性
  • 軽量性
  • 高速なパフォーマンス

により、現代の開発ニーズに対応する強力な Atomic CSS エンジンです。
UnoCSS は開発者にとっての新しい選択肢として注目されています。

この記事では、UnoCSS の基本的な特徴や使用方法について紹介しましたが一部のみです。
UnoCSS はさらに多くの機能やカスタマイズオプションを提供しています。
この記事を読んでくださった方の中で公式ドキュメントを読んでくれる方がいればめちゃ嬉しいです。

💚 最後に

この記事の執筆にあたって GANGAN さんにレビューしていただき、たくさんのアドバイスをもらいました。
本当にありがとうございます。

https://github.com/shinGangan/comm_vue_nuxt/issues/54


UnoCSS はまだ日本国内では広く知られていないかもしれません。
しかし、その優れた設計思想や特徴を理解し、導入を検討する価値は十分にあります。
この記事で少しでも UnoCSS について知ってくれたり、選択肢の一つに加えてもらえれば幸いです。

さらに詳しい情報や具体的な使い方については、今後以下のような記事を執筆予定です。

  • もっと詳しく
    公式ドキュメントの翻訳をベースにした詳細な解説記事
    • 設定
    • 公式プリセット
  • 人気フレームワークとの比較
    Tailwind CSS や Windi CSS などの他の CSS フレームワークとの比較記事

これらの記事もぜひご期待ください。

2024.08.18 追記
公式プリセットについての紹介記事を公開しました。
https://zenn.dev/comm_vue_nuxt/articles/what_is_unocss_official_presets


UnoCSS の魅力をもっと知りたい方は公式サイトやコミュニティリソースを活用して、積極的に情報を収集してみてください。

今後 UnoCSS ユーザがもっと増えて、日本語情報が増えることを強く願っています。
一緒にコミュニティを盛り上げていきましょう 💪

最後まで読んでいただきありがとうございました!

GitHubで編集を提案
Vue・Nuxt 情報が集まる広場 / Plaza for Vue・Nuxt.

Discussion

ピン留めされたアイテム
Anthony FuAnthony Fu

ご紹介ありがとうございます!

(日本語を勉強中なので、UnoCSS について何か質問があればお気軽に聞いてください :P)