Tailwind v4のビッグウェーブに乗る

この記事は ITソルーション室 Advent Calendar 2024 11日目の記事です。

はじめに

こんにちは!ここのえです。21卒OBです。arkwくんに誘われて参上しました。
現役生の方で顔合わせした方は少ないですが、ICON元会長・LT運営・はまりあ創設者と言うと若干しっくりくる方もいるかもしれません。在籍時はラックサーバを持ち込んだり、Kinectを弄ってVTuber配信システムを作ったりしてた怪しい人です。ちなみにエディタは Vim 派です。

今回はWebフロント関係で寄稿です。対戦よろしくお願いします。

普段はこのキプちゃんでVRCにいます よかったら仲良くしてね

Tailwind v4のBetaがリリース!

オープンソースのCSSフレームワークの中でも、破竹の勢いでBootstrapを蹴飛ばしBulmaを置き去りにし、現在も猛威を振るっているTailwind CSSくんですが、2024/11/22に v4 beta 1 がリリースされました!

Tailwind CSS v4.0 Beta 1 - Tailwind CSS
After a long alpha period, we're excited to release the first public beta of Tailwind CSS v4.0.

v4で最も注目すべき点は最適化によってビルド速度が大幅に向上した所ですが、他にもブラウザのサポート状況の変化によりコンテナクエリの標準サポートに加え、新たなユーティリティクラスが数多く追加されています。1から100まで解説していくと半端ない分量になってしまうので、特に注目したい点を幾つかピックアップして紹介していきます。

そもそもTailwindって何?なにが嬉しいの

もうさァッ 無理だよ CSSわかんないんだからさァッ
フロントをもっと勉強しないとさァッ

という声が聞こえてきた気がしたので、一応Tailwind CSSについてざっと説明しておきます。そんなん知っとるわ!という方はこのセクションは読み飛ばして頂いて結構です。

Tailwindを使ったコードはこんな感じです。パッと見で何をしているか何となくわかると思います。

HTML
<button class="m-2 px-4 py-2 bg-cyan-400 rounded-md font-black text-white">
  Click!
</button>
こんな感じになります

これらの指定されているクラスは、 m-mergin 、 px-py-padding です。 bg- は言わずもがな background-color です。このようなCSSに対応したクラスを「ユーティリティクラス」と呼び、この組み合わせでデザインを行っていくというのが、Tailwind CSSのアプローチです。

「こんなんインラインスタイルと変わらんやん!」と一見錯覚しますが、実際にはそうではありません。md: lg: のようなbreakpointによる分岐を行うことができ、レスポンシブ対応も万全です。 hover: でホバー時のスタイル変更、 dark: によるダークモードの色分岐等、モダンWeb開発に対応できるような機能が多く存在します。

それ故に既存のBootstrap, Blumaのようなフレームワークと大きく性質が異なり、Tailwind自体は何のデザインテンプレートを持っていません。パッと適当にモックアップを作ったり、デザインは二の次の業務用アプリケーションを作る目的には最適とは言えません。逆にデザインを凝りたい、独自性を出したいが、CSSは素早く書いてトライアンドエラーを繰り返したい、という目的ではTailwindは最適です。

ちなみに「クラス大量でHTML気持ち悪くならん?」というのは決して否定はできないです……。ただしVueやReact、Svelteのようなフレームワークが主流となった現代Web開発では、基本的にコンポーネント単位でファイルを分離するので、HTMLが肥大化する場面がそもそも少ないため、さほど問題にならないですし、HTMLとCSSの反復横跳びの必要がなくなり、デザインの修正がやりやすくなるメリットもあります。Tailwindのその辺りの指摘は各地で議論されているので、色々読んでみると面白いのでオススメです。

なぜ Tailwindcssなのか? CSSのパラダイムを振り返ってみた - Qiita
なぜ Tailwind が人気になったのか?自分なりに納得するために悶々と考えてみました、という日記です。具体的なコードについては触れません。抵抗感を感じているコーダーの人の一助になれば嬉しい…

Tailwind v4 betaの導入

今回はTypescript+Vite+Vue3の環境への導入を想定します。ありがたいことにTailwind v4から、Vite向けのプラグインが用意されるようになり、導入手順が簡素化されました。v3と異なり、npm install postcss autoprefixer する必要がありません。これに伴い導入方法も変わっているため注意が必要です。

Shell
# betaなので @nextの別パッケージになっています。正式版になったら変わるかも?
npm install tailwindcss@next @tailwindcss/vite@next

Viteのプラグイン化されたので、 vite.config.ts にTailwindプラグインを追加します。

vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import tailwindcss from "@tailwindcss/vite"; // <-これ

export default defineConfig({
  plugins: [
    vue(),
    tailwindcss(), // <-プラグインに追加
  ],
})

メインCSSでインポートして導入完了です。簡単!

style.css
@import "tailwindcss";


Tailwind v4 新機能

ここから本題です。v4で個人的にうれしくなったところをピックアップ。

エンジン見直し、ビルドの高速化

v4.0ではエンジン回りが1からリライトされて、ビルドの大幅な高速化がされています。具体的にはフルビルドで3.78倍、新しいCSSファイルを含むインクリメンタルビルドは8.8倍、新しいCSSファイルを含まない差分だけのインクリメンタルビルドは182倍(!?)高速化されました。

まあ実をいうと、元々Tailwindのビルドってかなり高速なので、個人開発の規模だと「フルビルドが200ms短縮された!」って言われてもあまり恩恵があるかというと微妙なんですが……。なんにせよ早いのは正義ではあります。

Tailwind CSS v4.0 Beta - Tailwind CSS
Preview what's coming in the next version of Tailwind CSS.

tailwind.config.jsのコンフィグはCSSへ変更

v3以前はTailwindのプロジェクト設定は tailwind.config.js で行っていましたが、これがCSS内で指定するように変更されます。CSS-first configuration 、声に出して読みたい英語。

Tailwind CSS v4.0 Beta - Tailwind CSS
Preview what's coming in the next version of Tailwind CSS.

一例としてv3のうちのサイトの tailwind.config.js はこんな感じ。独自カラーの設定やフォントの設定、プラグイン、対象ファイルの指定などを行っています。

tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: ['./resources/**/*.blade.php', './resources/**/*.ts', './resources/**/*.vue'],
  theme: {
    colors: {
      black: '#000000',
      white: '#ffffff',
      primary: '#231815',
      gray: '#C2C2C2',
      link: '#35B5E9',
      'dark-gray': '#D9D9D9',
      'on-dark-gray': '#8F8C8C',
      bgcolor: '#EBEBEB',
      'linkpage-secondary': '#727C88',
    },
    fontFamily: {
      inter: ['Inter', 'sans-serif'],
      mplus: ['"M PLUS 2"', 'sans-serif'],
    },
    extend: {},
  },
  plugins: [require('@tailwindcss/container-queries')],
}

これがCSSファイルに直書きになり、CSS変数と独自方法での記述に変更されました。カラーの指定がCSS内なのでIDEのカラーピッカー機能などが使えますし、ドキュメントを見る限り oklch() のような関数も使えるみたいです(前はカラー指定だけだった気がするのですが違ったらゴメンナサイ)。

style.css
@import "tailwindcss";
@plugin "@tailwindcss/container-queries";
/* ↑ はあくまで例です。このプラグインはv4で無くなったので注意!(後述) */

@source "./resources/**/*.blade.php";
@source "./resources/**/*.ts";
@source "./resources/**/*.vue";

@theme {
    --color-black: #000000;
    --color-white: #ffffff;
    --color-primary: #231815;
    /* and more... */

    --font-inter: "Inter", "sans-serif";
    --font-mplus: "M PLUS 2", "sans-serif";
}

ちなみにJetbrains IDEでは既に補完が表示されました。でも Unknown at-rule になるのでサポートはまだかも。

変数や @source, @pluginのような補完は出ます
でもこうなっちゃう

ESLint v8~のFlat Configに似たコンフィグの大幅変更ですが、フルサポートではないようですが、tailwind.config.js のレガシー互換モードも用意されています。

CSS
@config "../../tailwind.config.js";

ESLintのFlat Config周りは 六間坂上 Advent Calendar 2024 1日目 で書いてます。こっちも良かったらどうぞ。

coreライブラリでContainer Queryがサポート!

v4から標準ライブラリで

Container Queryがサポートされました
Tailwind CSS v4.0 Beta - Tailwind CSS
Preview what's coming in the next version of Tailwind CSS.

思わずワードアートを出してしまうほどの喜びです。コンテナクエリ( @Container )はCSSの新機能で、昨年2月にFirefoxが対応したことにより、全てのモダンブラウザで対応になりました。簡潔にまとめると、レスポンシブ対応向けの機能であり、親要素のサイズに合わせて子要素のスタイルを調整できるものです。これが登場するまでは、メディアクエリ( @media )でブラウザの幅高さから調整するか、Javascriptで何とかするしかありませんでした。珍妙なサイズのデバイスが跳梁跋扈する現代では非常にありがたみのある機能です。

v3以前のTailwindでは @tailwindcss/container-queries というプラグインを導入する必要がありましたが、不要になりました。プラグインに分離されている関係で不都合をして、結局導入を諦めた記憶があるのですが、今後はそんな心配をしなくても良さそうです。

また標準対応に伴い、Tailwindの通常のメディアクエリ分岐と同様に、コンテナクエリにも @max-* のbreakpoint基準の最大サイズ指定が追加されました。これにより min-max を自由に指定できるようになったため、コードの見通しがかなり良くなります。

例として、breakpointが md から lg の時だけ背景色を赤に変えてみます。

HTML
<div class="@container">
  <div class="bg-cyan-500 @min-md:@max-lg:bg-red-500">
    コンテナサイズがmd-lgの時、背景が赤になります
  </div>
</div>

3D Transform

新たに rotate-x-*, rotate-y-*, scale-z-*, translate-z-* が追加され、Transform 3Dに対応しました。Tailwindは簡易的なアニメーションを実装するのに結構役立っていたので、ちょっとした3D効果を得られるようになったのは便利だと思います。

マウスオーバーでアニメーションを作ってみましょう。

YamdaTaro.vue (<Template>)
<div class="perspective-distant">
  <p class="
    font-dokaben text-[#AE341F] text-9xl
    transform-3d origin-bottom rotate-x-89 transition-all duration-[3s]
    hover:rotate-x-0 hover:translate-y-5"
  >
    ド カ ベ ン
  </p>
</div>

強力なvariantsが追加

v4から強力なvariant(md:hover: みたいなprefix)が複数追加されました。v3以前もTailwindだけでCSSで弄るほとんどのデザイン操作はできるようになってはいますが、セレクタ関係についてはやや不完全な部分があり、頻繁に使うのにTailwindに標準で搭載されていないものもありました。

nth-*:

一つの例として、以下のCSSをTailwindで再現することを試みます。

Vue
<script setup lang="ts">
import {ref} from "vue";
const items = ref([
  {message: "Foo"},
  {message: "Bar"},
  {message: "Baz"},
  {message: "Hoge"},
])
</script>

<template>
  <div class="inline-flex space-x-10 mx-3 my-2">
    <div
        v-for="(item, index) in items"
        :key="index"
        class="color-box"
    >
      {{item.message}}
    </div>
  </div>
</template>

<style scoped>
.color-box {
  background-color: cyan;
}

.color-box:nth-last-child(2) {
  background-color: darkcyan;
}
</style>

color-box クラスに対して、:nth-last-child(2) で末尾から2つ目の要素の背景色を darkcyan に変更しています。これをTailwind v3以前で実装しようとすると、以下のようになります。

Vue
<script setup lang="ts">
import {ref} from "vue";

const items = ref([
  {message: "Foo"},
  {message: "Bar"},
  {message: "Baz"},
  {message: "Hoge"},
])
</script>

<template>
  <div class="inline-flex space-x-10 mx-3 my-2">
    <div
        v-for="(item, index) in items"
        :key="index"
        class="bg-cyan-300 [&:nth-last-child(2)]:bg-cyan-700"
    >
      {{ item.message }}
    </div>
  </div>
</template>

<style scoped>
</style>

この []Arbitrary Variants と呼ばれるもので、Tailwindに存在しないセレクタを使う場合はこのような手を使う必要があります。nthnot のようなセレクタはよく使うので、若干手間になっていました。

しかし遂にv4で、nth 系や not など、多くのvariantが追加されました。 nth 系では nth-*, nth-last-*, nth-of-type-*, nth-last-of-type-* が追加され、上記のコードもこのように書き換えられます。かなりスッキリしますし、コードを読んだ時に直感的に理解できてとても良いです。

Vue
<template>
  <div class="inline-flex space-x-10 mx-3 my-2">
    <div
        v-for="(item, index) in items"
        :key="index"
        class="bg-cyan-300 nth-last-2:bg-cyan-700"
    >
      {{ item.message }}
    </div>
  </div>
</template>

オマケ:v3時代の(やや)つらいセレクタ判別

v3以前でややこしかったのが、Arbitrary Variantsでのセレクタ指定の問題で、&: だけを使っているうちはいいのですが &> だと子セレクタ、&_ だと子孫セレクタになります。 つまり[&:nth-last-child(2)]:[&>nth-last-child(2)]:[&_nth-last-child(2)]: は全然意味が違うのでこれが出てくると毎回コードを凝視する必要があります👀 v4以後は [& を見かける回数がグッと減るので、セレクタを凝視する負担がかなり軽減されてうれしいという構図です。

not-*:

not についても同様で、これが追加されたのもかなり Powerful です。focusnot の時のパターンも、以下のように書き換えられるようになりました。スッキリ度が全然違いますね。Tailwind v4のVariants気持ち良すぎだろ

HTML
<!-- Old-school style -->
<textarea class="[&:not(:focus)]:bg-cyan-400">
  Focus?
</textarea>

<!-- v4 -->
<textarea class="not-focus:bg-cyan-400">
  Focus?
</textarea>

starting: (@starting-style)

これはまだCSSの方もあまり知られてないんですが、2024/8/6のFirefox 129で全ブラウザ対応になったばかりの @starting-style という新ルールがあります。これはトランジションされる要素の初期値を設定するルールです。詳しくはMDNを覗いてみてください。

@starting-style - CSS: カスケーディングスタイルシート | MDN
@starting-style は CSS のアットルールで、トランジションさせる要素に設定されるプロパティ群の開始値を定義するために使用します。これらのプロパティは、最初に要素のスタイルが更新されたとき、つまり要素が前回読み込まれたページ...

Tailwindではv4で早速サポートされ、starting: variantを使う事で @starting-style を使用することができます。一例としてボタンを押したときにdialogを表示するような場面で、opacityの初期値を設定するのに使えます。

HTML
<div class="p-3">
  <button
      popovertarget="dialog"
      class="bg-cyan-500 text-white p-2 rounded-xl"
  >
    Open Dialog
  </button>
  <div
      popover
      id="dialog"
      class="bg-cyan-700 m-auto text-white p-10 rounded-lg
       opacity-0 transition-opacity duration-1000 open:opacity-100 starting:open:opacity-0"
  >
    Hi! My name is Tailwind!
  </div>
</div>

まとめ

最近結構な数のWeb屋に愛されているTailwindくんですが、v4のアップデートを俯瞰してみると、ビルドスピードの高速化や痒い所に手が届くユーティリティ、バリアントの追加、脱tailwind.config.js からのCSS Configurationなど、いい方向に正統進化していると思います。

もちろんメジャーバージョンアップなので、コンフィグ変更を筆頭として、v3空の更新についてはドキュメントを読みながら慎重に作業を行っていく必要もあります。またIDEの対応が追い付いていないため、@theme ルールなどエラーが表示されてしまう箇所もあり注意が必要です。

ESLintやPrettier周りのサポートが充実してくれば、CSS内コンフィグの自動並び替えやユーティリティクラスのソートなども出来るようになると思うので、現実的にはその辺りのタイミングがv3からの乗り換えタイミングになるんじゃないかな~と思います。

実のところ in-* variantとか inset-shadow-*inset-ring-* とかに加え、Vue/Svelteでの @apply 使用時にテーマをインポートする話とか……書きたいことはまだまだ山のようにあるのですが、これをやり始めるとただのv4ドキュメントの英日翻訳記事になってしまいそうなので、この辺で止めておきます。

Tailwindはとっつきにくい印象はありますが、その実「細かなCSSを簡単に素早く書ける」みたいな側面が強いので、Webデザイン慣れしていない方にもお勧めできます。CSSに苦手意識はあるけど、いい感じのWebデザインに挑戦してみたい……と思ったら、ぜひ一度触ってみてください!

コメント

タイトルとURLをコピーしました