🍣

Tailwind CSS を敬遠していた僕が、一転してブログを書く程大好きになった話

2023/12/08に公開

※この記事は ヌーラバーブログリレー2023 for Tech Advent Calendar 2023 8日目の記事です。明日は Hiroyuki Sakamoto さんの記事です。


Tailwind CSS 使っていますか?マークアップエンジニアやフロントエンドエンジニアにとって、Tailwind CSS は避けて通れない技術のひとつになってきています。

最近話題になった catnose さんの「しずかなインターネット」も Tailwind CSS が使われていました。また、AI で UI を作成できる Vercel の「v0」も Tailwind CSS ベースで作られますね。

https://sizu.me/

https://v0.dev/

しかし、タイトルの通り、僕は少し前までは Tailwind CSS に対して少し距離を置いていました。ですが、さすがにフロントエンドエンジニアとしてトレンドの技術を無視するわけにはいけないと思い、実際に Tailwind CSS を触ったり、いろんな Tailwind CSS に関する記事を読んで、今では早く実際のプロジェクトでも使ってみたい!と思うくらい大好きになっています。

僕と同じく敬遠している方も多いのではないでしょうか?ぜひ、そういう方にこの記事を読んでいただいて、「Tailwind CSS 触れてみよう」と思うきっかけになれば幸いです。

この記事で書くこと・書かないこと

今回は Tailwind CSS の詳しい説明はせず、自分が「使えそう!良さそう!」と感じたポイントを中心に書きます。

書くこと

  • Tailwind CSS を敬遠していた理由(デメリット)
  • Tailwind CSS のいいところ
  • Tailwind CSS の嫌いな部分を解消する方法

書かないこと

  • Tailwind CSS に関する具体的な説明
  • Tailwind CSS の実践例
  • Tailwind CSS と他の CSS ライブラリとの比較

Tailwind CSS を敬遠していた理由

まずは、なぜ僕が Tailwind CSS を毛嫌いしていたのか、その理由を説明します。

1. 見にくい

まずは、なんと言っても Tailwind CSS の可読性の低さです。

CSS クラスを使ったスタイルの定義が HTML 内に大量に列挙されるため、コードの見通しが悪くなりがちです。そういう HTML を見るとつい反射的にエディタを閉じたくなってしまいます。。。

例えばこういうコード↓

const Button: React.FC<ButtonProps> = ({
  children,
  color = "primary",
  size = "md",
  disabled,
  ...props
}) => (
  <button
    className={`inline-flex justify-center items-center border-0 text-white font-bold [&:focus:not(:focus-visible)]:outline-none ${ color === "secondary" ? "bg-green-600 hover:bg-green-700" : "bg-blue-500 hover:bg-blue-700" } ${ size === "lg" ? "py-3 px-10 text-lg" : size === "sm" ? "py-1 px-6 text-base" : "py-2 px-8 text-base" } ${ disabled ? "opacity-30 cursor-not-allowed pointer-events-none" : "cursor-pointer" }`}
    disabled={disabled}
    {...props}
  >
    {children}
  </button>
);

これはまだ button 要素しかないのでまだましですが、他の要素を追加するとさらに見にくくなりますね。可読性が低いとそれを読み解くのに時間もかかっちゃいますし、メンテナンスも大変ですよね。また、スタイルの重複に気付きにくいといったデメリットもあります。(absoluterelative を同時に使ってしまったり)

あとは、HTML の見通しが悪くなることで HTML 要素や属性もわかりにくくなるので、セマンティックな HTML マークアップに集中することが少し難しくなります。これはマークアップエンジニアにとってはちょっと辛いポイントです。(他のライブラリでも同じような問題はありますが)

2. 慣れない

CSS 歴が長い方ほど Tailwind CSS に慣れにくいのではないかと思っています(自分もそうなので勝手に思っているだけかも)。Tailwind CSSは、多数の CSS クラス名を覚える必要があるので、それを覚えるよりも普通に CSS を書いた方が早いですからね。

ドキュメントは非常に充実していますが、慣れるまでは必要な情報を探しながら作業する必要があるので時間がかかってしまいます。さらに、チーム全体での習得にも時間が必要なので、なかなか手を出しづらいというのもあると思います。

https://tailwindcss.com/docs/installation

3. 複数 CSS クラスへの抵抗

この理由も CSS 歴が長い人は共感してもらえるのではないかなと思います。正直時代を逆行している感が否めませんでした。

というのも、10年前くらいに OOCSS という CSS 設計の走りのようなものが流行りました。これも複数 CSS クラスをふんだんに使った設計方法です。プロジェクトが大きくなるとその分必要な CSS クラスもどんどん増えていって、メンテが大変になって、複数 CSS クラスの使用に疲弊感を感じた人も少なくなかったと思います。

そこから SMACSSBEM, FLOCSS のように新しい CSS 設計が生まれていくわけですが、どの設計方法もグローバルな CSS でどうやって擬似コンポーネント化するか、スコープ化するかという課題を解決するための歴史という認識です。

後で説明しますが、今は React, Vue, Angular などのフレームワークでコンポーネント設計ができるので、正直この CSS 設計という概念は必要なくなってきたのかな、と個人的には思っています。

このような理由から、私は当初 Tailwind CSS を敬遠していました。しかし、ただ嫌っていたというわけではなく、Tailwind CSS を使うことのメリットも感じていました。

Tailwind CSS のいいところ

Tailwind CSS には、上記の(個人的な)嫌いな理由を除けば多くのメリットがあります。

1. 早い

Tailwind CSS は今話題のゼロランタイム CSS です。styled-componentsemotion などランタイム CSS in JS に比べると早いという大きなメリットがあります。

また、Next.js が v13 で App Router という機能をリリースし、サーバー側で React コンポーネントをレンダリングする React Server component が App Router ではデフォルトで適用されますが、Next.js の公式にも書かれている通り、React Server component ではランタイムな CSS in JS はそのままでは使えません。そのため、ゼロランタイム CSS な Tailwind CSS が注目されてきています。(use client は書きたくない)

ゼロランタイム CSS in JS についてやパフォーマンスの差については以下の記事を参考にさせていただきました。

https://zenn.dev/poteboy/articles/e9f63b87b3cd69

https://zenn.dev/maple_siro/articles/fd29bb6a051971

2. UI に一貫性が出る

次に、UI デザインに一貫性を持たせやすいというメリットがあります。Tailwind CSS ではデフォルトで幅・高さ・余白などは 4 の倍数で設定されています(カスタマイズ可能)。例えば p-1padding: 4px; となり p-4padding: 16px; に、p-8 だったら padding: 32px のように変換されます。

https://tailwindcss.com/docs/customizing-spacing

Arbitrary values という機能を使って p-[11px] などを使わない限り、基本的には設定したルールから変換される値や単位を使うことができるので、UI に一貫性を持たせることができます。

また、サイズや余白だけでなくフォントサイズや色も、設定した値を元に変換されるので、人によって書き方が違ってたり、一部統一感のない UI になってたり、という問題が起こりにくくなります。

プロジェクト毎に設定することができるので、デザイントークンとの相性もよく、デザインシステムのコンポーネントカタログの実装にも向いてそうな印象です。

3. 崩れにくい

上にも関連していますが、Tailwind CSS では良くも悪くも 1px 単位で細かく調整がしにくいです。これは UI が崩れにくくなるという利点にもつながりますね。一度ルールを元に設定されたスタイルは安定するので、予期せぬ変更によるデザインの崩れが少なくなります

ピクセルパーフェクトなスタイリングをしようと思うと少し難しくなるかもしれません。Arbitrary values を使えばできなくはないのですが、その分コードも複雑になってしまいますね。そういう用途がある場合は CSS Modules などの別のツールも併用して使うという選択肢もあるかもしれません。

以上が僕が感じていた Tailwind CSS のメリットの一部です。これだけ使うメリットが大きいので、あとは最初に嫌いな部分が解消されれば、もう使わない理由はなくなります。では、どうやって僕がそれらのデメリットを解消したかをお話しします。

Tailwind の嫌いな部分を解消する方法

1. 見にくいを解決

Tailwind CSSの「見にくい」という問題は、Tailwind Variants の使用によって解決しました。

Tailwind Variants は以下の記事を見て知りました。

https://zenn.dev/yend724/articles/20230603-wgnqrgmj8kymzpev

Tailwind Variants とは、従来の Tailwind CSS の機能に Variant API を組み合わせたもので、Tailwind CSS のスタイルの拡張や上書きを容易にしてくれます。内部で tailwind-merge というライブラリを使って処理されているので、クラス名を変数にしたり、スタイルの重複を自動で上書きしてくれたりします。

Tailwind Variants を使って以下のコードのように CSSを書いているかのようにルールごとに改行したり、それぞれの Variant 毎のスタイルをわかりやすく書くことができます。

先ほど見にくいサンプルコードを Tailwind Variants を使って書いてみました。

import { tv } from "tailwind-variants";

const button = tv({
  base: `
    inline-flex justify-center items-center
    border-0
    text-white font-bold
    cursor-pointer
    [&:focus:not(:focus-visible)]:outline-none
  `,
  variants: {
    color: {
      primary: "bg-blue-500 hover:bg-blue-700",
      secondary: "bg-green-600 hover:bg-green-700",
    },
    size: {
      sm: "px-6 py-1 text-base",
      md: "px-8 py-2 text-base",
      lg: "px-10 py-3 text-lg",
    },
    disabled: {
      true: "opacity-30 cursor-not-allowed pointer-events-none",
    },
  },
  compoundVariants: [
    {
      color: "primary",
      disabled: true,
      class: "bg-gray-500",
    },
  ],
  defaultVariants: {
    color: "primary",
    size: "md",
  },
});

そして、HTML 側はこのようにシンプルな状態を保つことができるので、セマンティックな HTML マークアップに集中できますね

const Button: React.FC<ButtonProps & ButtonVariants> = ({
  children,
  color,
  size,
  disabled,
  ...props
}) => (
  <button
    className={button({ color, size, disabled })}
    disabled={disabled}
    {...props}
  >
    {children}
  </button>
);

少しコード量は増えますが、圧倒的にこちらの方がコードとしては見やすいです。

Tailwind Variants と同じようなツールとして cva というものだったり、探せば他にもあると思います。Variant API が必要なければ tailwind-merge を入れるだけでも良さそうです。

ちなみに、今話題の shadcn/ui も Tailwind CSS & cva を使って Variants ベースで UI コンポーネントが作られます。

https://ui.shadcn.com/

2. 慣れないを解決

次に、「慣れない」という問題は Tailwind CSS IntelliSense という VSCode の拡張機能を使うことで解決します。

https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss

このツールは自動補完や重複チェックを提供し、さらにスタイルの結果も表示してくれます。ドキュメントも合わせて使えば Tailwind CSS の習得はかなり早くなりそうです。個人的には Tailwind CSS を使うのであればこの拡張機能は必須ではないかなと感じています。

Tailwind CSS IntelliSense の自動補完を使っている様子のスクリーンショット。text と入力するだけで text から始まる CSS クラス名の候補をポップアップで表示してくれる

ちなみに Tailwind Variants と一緒に使うには少し設定が必要です。以下の GitHub Issue に VSCode の設定方法が書かれていましたので参考にさせていただきました。

https://github.com/nextui-org/tailwind-variants/issues/17

3. 複数 CSS クラスへの抵抗を解決

最後は、「複数 CSS クラスへの抵抗」の問題です。

先ほども軽く触れましたが、今は React などのフレームワークを使ってコンポーネント設計をする場合は CSS 設計の必要性がなくなってきました。なので Tailwind CSS のようにユーティリティファースト CSS と呼ばれるものは、実は現代のウェブ開発においてはむしろ理にかなったアプローチではないかとも考えることができます。CSS クラス命名に悩む時間も少なくなりますしね。

ユーティリティファースト CSS の概念については以下のドキュメントを参考にしました。ここにも書かれているように、再利用したいものはパーツ(コンポーネント)として切り出すので、CSS クラスまでコンポーネントと対応させるのは冗長なんですよね。

https://gihyo.jp/article/2023/07/tailwindcss-practice-01#gh7yYeM_Sn

補足:ベテランマークアップエンジニアに聞いてみた

とあるイベントで福岡の重鎮的なマークアップエンジニアのお二方とお話しする機会があったので、Tailwind CSS にどんな印象を持っているかを聞いてみました。お二人とも CSS 歴は長いのでてっきり僕と同じような印象をお持ちだと思っていましたが、意外な回答が返ってきました。

最近は Astro と Tailwind CSS を使ってよく Web 制作の仕事をしよるばい。10ページくらいの案件にはちょうどいいけんね〜。

前は styled-components とかも使いよったけど Tailwind CSS は環境構築もばり楽やし、アップデートで壊れるみたいなことも基本なかろ?環境にも依存せんしメンテも楽やし最高ばい。

なるほど。僕の考えが古かっただけでちゃんとみんな実務でも使ってるんですね。。。みんなさすがばい。

確かに環境に依存しない・アップデート作業で動かなくなるみたいなこともほとんどないだろうからそこも大きなメリットのひとつだなーと気付かされました。

まとめ

この記事で紹介した Tailwind Variants や Tailwind CSS IntelliSense などのツールを活用することで当初感じていた Tailwind CSS のデメリットは解決でき、さらに多くのメリットを享受することができます。

現在、多くの企業がデザインシステムの導入に積極的に取り組んでいます。このような状況の中で、ユーティリティファースト CSS である Tailwind CSS は、その真価を発揮します。早さ、UI の一貫性、崩れにくさといったメリットを踏まえると、Tailwind CSS は UI エンジニアリングにおいて非常に適した選択肢と言えます。

そして、最後に伝えたいことは、Tailwind CSS に限らず、新しい技術に対して否定的な態度を取るのではなく、実際に試してみることの重要性です。新しい技術をまず一度使ってみることで、技術選定の際の選択肢が広がり、より良い判断ができるようになります。Tailwind CSS はその一例に過ぎませんが、常にオープンなマインドで新しい技術にアプローチすることが、技術者としての成長に繋がると改めて思います。

Discussion