[キャッチアップ] TailwindCSS

スクラップについて
なんとなく食わず嫌いしてた tailwindcss
について、使いたい場面が出てきたので改めて確認する。
ユーティリティクラスが色々デフォルトで入ってるCSSフレームワークで、ゼロランタイムに出来てカスタマイズ性が凄いぐらいの認識からのスタート。

サンドボックス環境作る
今回は Vite + React + TS で。
$ yarn create vite
# React + TS で作る
$ yarn add tailwindcss
$ npx tailwindcss init
tailwind 用の設定ファイルが作られる。この辺いじるのがだいぶ先だと思うけど。
/** @type {import('tailwindcss').Config} */
export default {
content: [],
theme: {
extend: {},
},
plugins: [],
}

Tailwind はゼロランタイム
Tailwind CSS works by scanning all of your HTML files, JavaScript components, and any other templates for class names, generating the corresponding styles and then writing them to a static CSS file.
It's fast, flexible, and reliable — with zero-runtime.
ということらしい。膨大なクラスを読み込むんじゃなくて、実際に使用されているクラスのみをプリプロセスで読み込むんだ。
具体的には PostCSS のプラグインとして機能するらしい。だから webpack なら postcss-loader とかなのかな。

対象コードを指定する
設定ファイルでスキャン対象ファイルを指定。
/** @type {import('tailwindcss').Config} */
export default {
content: ["index.html", "./src/**/*.{html,js,ts,jsx,tsx}"],
theme: {
extend: {},
},
plugins: [],
};

入力ファイルの設定
tailwind に読ませるルートファイルを用意
@tailwind base;
@tailwind components;
@tailwind utilities;

-
base
がリセットCSSみたいなもの -
utilisites
が各ファイルで使用されているユーティリティクラス -
components
はなんか tailwind 用のカスタムコンポーネントのやつらしい

CLI で 出力する
PostCSS プラグインとして機能するって書いてたけど、普通に CLI でもいけるみたい。
$ npx tailwindcss -i ./src/input.css -o ./dist/output.css --watch
掲載は省略するけど、リセットCSSっぽいのだけ出力された。
出力ファイルを読み込むタグを HTML に追加する。
<link href="/dist/output.css" rel="stylesheet">

HTML で使ってみる
こんなタグを追加する。
<h1 class="text-3xl font-bold underline">Hello, Tailwind</h1>
tailwind が再ビルドされて以下みたいな定義が追加された。
.text-3xl {
font-size: 1.875rem;
line-height: 2.25rem;
}
.font-bold {
font-weight: 700;
}
.underline {
text-decoration-line: underline;
}
逆にタグを消して再ビルドすると、ちゃんとCSS定義も消える。

React コンポーネントで使ってみる
<h1 className="text-3xl font-bold underline">Vite + React</h1>
なんか追加設定いるかと思ったけど普通に適用された。

どうやらクラスの利用情報を抽出する purgecss の仕組みらしい

と思ったが今は使われてない・・・?
Since Tailwind no longer uses PurgeCSS under the hood, we’ve renamed the purge option to content to better reflect what it’s for:

vscode 拡張を設定する
Tailwind は @tailwind
@apply
みたいな拡張ルールがあったり、ユーティリティクラスがたくさんあったりするので、それを補完できるようにする。
これをインストールする
補完が効くとか当たり前機能もよいけど、ユーティリティクラスに対してプレビュー入るのイケてる。
Prettier プラグイン入れるとクラス名の順番揃えられるらしい。

ユーティリティファーストな考え
従来のCSSじゃなくてユーティリティファーストなクラスを使うことで
- クラス名を考えるのに苦労せずに済む
- 特にレイアウト用途だけのラッパー要素など (
sidebar-inner-wrapper
)
- 特にレイアウト用途だけのラッパー要素など (
- CSS の誇大化を防げる
- 機能拡張ごとにCSSも増えていってしまう
- これはコンポーネント指向してけば回避できるかも?
- 機能拡張ごとにCSSも増えていってしまう
- CSS のスコープを考慮せずに変更できる
- これもコンポーネントに閉じたスタイリングできれば大丈夫
ならユーティリティクラスじゃなくてインラインスタイルを直接書けばよいのでは説があるが、ユーティリティクラスを使うことで
- デザインの一貫性を担保できる
- 特にデザインシステム構築に強力
- メディアクエリはインラインでは描けないが、ユーティリティクラスなら使える
- ホバー、フォーカスといった擬似クラスも扱える\

こりゃ便利そうだ。
.hover\:font-bold:hover {
font-weight: 700;
}
@media (min-width: 640px) {
.sm\:text-left {
text-align: left;
}
}

擬似クラス(疑似要素)

<li class="flex py-4 first:pt-0 last:pb-0">
こういうの便利ね。先頭と末尾には余計な空白入れないみたいなの。
flex で重ねて gap 指定にすれば良いのではってのはあるけど。

<input type="text" value="tbone" disabled class="mt-1 block w-full px-3 py-2 bg-white border border-slate-300 rounded-md text-sm shadow-sm placeholder-slate-400
focus:outline-none focus:border-sky-500 focus:ring-1 focus:ring-sky-500
disabled:bg-slate-50 disabled:text-slate-500 disabled:border-slate-200 disabled:shadow-none
invalid:border-pink-500 invalid:text-pink-600
focus:invalid:border-pink-500 focus:invalid:ring-pink-500
"/>
こういうのを見ると流石にウッとなるけど、普通にCSS書いたとしてもそれなりに長く複雑になるからええか。

親要素の状態に基づいて子要素のスタイルを変えるの凄い!
<a href="#" class="group block max-w-xs mx-auto rounded-lg p-6 bg-white ring-1 ring-slate-900/5 shadow-lg space-y-3 hover:bg-sky-500 hover:ring-sky-500">
<div class="flex items-center space-x-3">
<svg class="h-6 w-6 stroke-sky-500 group-hover:stroke-white" fill="none" viewBox="0 0 24 24"><!-- ... --></svg>
<h3 class="text-slate-900 group-hover:text-white text-sm font-semibold">New project</h3>
</div>
<p class="text-slate-500 group-hover:text-white text-sm">Create a new project from a variety of starting templates.</p>
</a>

レスポンシブデザイン
こういうやつ
<!-- Width of 16 by default, 32 on medium screens, and 48 on large screens -->
<img class="w-16 md:w-32 lg:w-48" src="...">
By default, Tailwind uses a mobile-first breakpoint system, similar to what you might be used to in other frameworks like Bootstrap.
What this means is that unprefixed utilities (like uppercase) take effect on all screen sizes, while prefixed utilities (like md:uppercase) only take effect at the specified breakpoint and above.
なんでそれがモバイルファーストなんだろうって思ったけど、ビューポートが広い場合の指定を明示しなければならない=デフォルトではモバイルビューにも適用される=モバイルファーストに実装する必要があるってことか。
モバイル向けの個別対応をするんじゃなくて、モバイルがデフォルトで、PCが個別対応ってことだ。

ダークモード
なるほど
ダークモード指定はメディアクエリじゃなくクラスベースにすることもでき、Webサイト内に切り替えUIを設ける作り方にも出来る。

スタイルの再利用
マルチカーソルを活用して最適化しろなんてガイド始めてみたわ。
@layer
と @apply
を活用して再利用可能なスタイルの定義が可能。なるほどぉ。
@layer components {
.btn-primary {
@apply py-2 px-4 bg-blue-500 text-white font-semibold rounded-lg shadow-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-400 focus:ring-opacity-75;
}
}
これも .btn-primary
が使用されてないと生成されないみたい。
でもこういう共通化・抽象化はなるべくしないほうが Tailwind の良さは引き出せるよとのこと。
まぁコンポーネントで切り出せば良いでしょとは思う。

カスタムスタイル
設定ファイル内でテーマの各種値を差し替えることができる
/** @type {import('tailwindcss').Config} */
module.exports = {
theme: {
screens: {
sm: '480px',
md: '768px',
lg: '976px',
xl: '1440px',
},
colors: {
'blue': '#1fb6ff',
'pink': '#ff49db',
'orange': '#ff7849',
'green': '#13ce66',
'gray-dark': '#273444',
'gray': '#8492a6',
'gray-light': '#d3dce6',
},
fontFamily: {
sans: ['Graphik', 'sans-serif'],
serif: ['Merriweather', 'serif'],
},
extend: {
spacing: {
'128': '32rem',
'144': '36rem',
},
borderRadius: {
'4xl': '2rem',
}
}
}
}

基本的なことはわかったのでヨシ!