
2026/05/16 18:14
Tailwind から距離を置き、CSS の構造化について学ぶようになりました。
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
Tailwind CSS を 8 年間使用した後、著者は保守負荷の増大に対処しビルドシステムの複雑性を低減するために、2 つの長期運用ウェブサイトを見送りを语义 HTML およびバニラ CSS に移行しました。この哲学的な転換は、「Tailwind と CSS の女性性」という論文における「重厚なフレームワークがコアとなる CSS 専門知識を損なう」という懸念から発せられ、巨大なファイルへの依存や外部ライブラリへの依存を避けることを目指しています。
新しいアーキテクチャはユーティリティクラスよりも语义構造を優先しつつ、重要な機能を精選して保持しています:Tailwind のリセットスタイル(例:
box-sizing)や .sr-only といった特定のユーティリティは一貫性の確保のためそのまま維持され、色は集約された colours.css ファイルで定義され、Tailwind に由来するフォントサイズの変数も併せて定義されます。不整合なマージンを使用せずに効率的にスペースを扱うために、「owl セレクター」戦略が採用され、レスポンシブデザインでは従来のメディアクエリではなく CSS Grid の機能(例:auto-fit)が依存しています。
将来への展望として、プロジェクトは共通パターンを集約し最小限のグローバルベーススタイルへと統合するためのボトムアップのアプローチを計画しています。開発ワークフローにはネイティブ ES モジュールが利用され、本番コードは静的な Go バイナリ
esbuild を用いてバンドルされます。この戦略により、グローバル CSS ルールの最小化でサイト間の一貫性が確保されるとともに、巨大で最適化されていないファイルの蓄積を防止し、将来の保守のための持続可能なモデルを確立します。本文
こんにちは!8 年前、Tailwind を発見したことを興奮して綴ったことがあります。当時は、CSS コードの構造化方法が全く理解できず、一見無秩序なコードを抱え込む選択肢か、それとも Tailwind かという二択を迫られましたが、後者を選べて本当に嬉しかったです。そのおかげで多数の小さなウェブサイトを作り上げることができました。
さて、最近 1 週間ほどかけていくつかのサイトを Tailwind から離れ、より意味のある HTML とバニラ(純粋な)CSS に移行するプロジェクトを行いました。この経験は非常に面白く刺激的でありましたので、私が学んだことをいくつかご共有します。
普段からフルタイムでフロントエンド開発には携わっておらず、CSS の学習も長年にわたって断続的に行ってきた者ですが、 Tailwind を通じて多くを学びました。
CSS の構造について考え始めた当初は、正直少し畏怖する気持ちもありました。「私、CSS の構造化そんなに得意じゃないからな……」と感じていたのです。しかし、その後、「CSS ライヤの全体像」や「2024 年の CSS 書き方」といったブログ記事を読むうちに、いくつかのことに気づきました。
- どんな CSS コードベースも、レイアウト、フォント、カラー、共通コンポーネントなど多様な要素を内包しています。
- これら各要素を管理するためにはシステムやガイドラインが不可欠であり、それがないとすぐに混沌に陥ってしまいます。
- Tailwind はこれらの一部の要素に対して既にシステムを提供しており、かつ私はそれらのシステムについては既に理解しています。「気に入っているシステムを模倣できないか?」という発想に至ったのです。
具体的には、Tailwind の以下のようなシステムがあります:
- リセット用スチールシート(リセットスタイル)
- カラーパレット
- フォントスケール
これらについて、私がこれから触れるいくつかの点をお伝えします。私の CSS コードベースにおける各側面に対する現状の確認と、今後課したいルールについては、一部は Tailwind を踏襲し、一部は独自の判断で行います。
1. リセット(Reset)
私は単純に
tailwind.css から最初の約 200 ラインほどをコピペして、Tailwind の「preflight styles(プリフライトスタイル)」を採用しました。
時間が経過するにつれて、Tailwind の CSS リセットとの間に深い絆が形成されてきたことを感じています。例えば、Tailwind はすべての要素に
box-sizing: border-box を適用することで、要素の幅にパディングが含まれるようにしているわけですが:
* { box-sizing: border-box; }
これらの設定を外して CSS を書くことに切り替えるのは私にとって大きな適応を必要とすることになるでしょう。また、Tailwind のリセットには他にも多くの設定(例えば
html { line-height: 1.5; } など)が含まれており、これらは下意識レベルで使い込まれているので、自分がどのようになっているか全く気付きません。
2. コンポーネント(Components)
ここが CSS の大部分を占める部分です。 このアプローチは、Vue や React のコンポーネント概念に精神的に通じるものであり、ウェブサイトのどこにも JavaScript が含まれていない場合でも同様です。基本的な考え方は以下の通りです:
- 各「コンポーネント」は独自のクラスを持ちます。
- あるコンポーネントの CSS は決して他コンポーネントの CSS と干渉しません。
- 各コンポーネントには個別の CSS ファイルが割り当てられます。
つまり、1 つのコンポーネントの CSS を編集しても、別のコンポーネントに思わぬ影響を与えることはありません。実際に変更を加えたいと思える CSS の約 80% は、これらのコンポーネント用ファイルに含まれているため、100 ライン程度のコンポーネントファイルを編集する際も、「この 100 ラインだけ考えてくれればいい」というシンプルな思考プロセスが可能になります。私にとっては非常に考えやすく整理されています。
例えば、以下のような HTML が
.zine という名前の「コンポーネント」を表す場合があります:
<figure class="zine horizontal"> <img src="whatever.jpg"> </figure>
対応する CSS は階層型セレクトル(ネスト Selector)を使い、以下のような見た目になります:
.zine { ... &.horizontal { ... } &.vertical { ... } &:hover { ... } }
現時点では、コンポーネント間の干渉を防ぐための程序的なアプローチ(Web Components や
@scope など)は行っていませんが、このような規約を設け、最善を尽くすことだけでも大きな改善だと感じています。次は、サイト全体の一貫性を維持しつつ、これらのコンポーネントを整列させるための規約についてです。
3. コロア(Colours)
colours.css ファイルには、必要に応じて使用する変数のようなものが多く定義されています。カラー使いは非常に難しく、今回のリファクタリングで以前の色彩使い方を見直す気にもなれず、このファイル自体は変更していません。ここで重視する唯一のガイドラインは、サイト全体で使用されるすべての色をこの 1 ファイルに列挙することです。
:root { --pink: #fea0c2; --pink-light: #F9B9B9; --red: #f91a55; --orange: rgb(222, 117, 31); ... }
4. フォントサイズ(Font sizes)
Tailwind で気に入っていた点は、「文字を大きくしたいな」と思ったら、
text-lg を書くだけで済むこと、もしさらに大きくしたければ xl や 2xl に置き換えるだけだった点です。その際に「em か px か rem か」を意識して記憶する必要もありませんでした。
そこで Tailwind に倣って以下のようにバリエーションを用意し、変数を定義しました:
--size-xs: 0.75rem; --line-height-xs: 1rem; --size-sm: 0.875rem; --line-height-sm: 1.25rem;
フォントサイズを設定する際は、以下のように記述します。Tailwind よりも少し冗長ですが、現時点ではこれで問題ありません。
h3 { font-size: var(--size-lg); line-height: var(--line-height-lg); }
5. ユーティリティ(Utilities)
複数のコンポーネントに共通して現れるような要素、例えばボタンなどは「ユーティリティ」と呼んでいます。Tailwind からいくつかのユーティリティクラスを借用しています(例:スクリーンリーダー用だけに表示させるための
.sr-only など)。このセクションは比較的小さく、ここでの変更には慎重にアプローチしています。
6. ベーススタイル(The Base)
「base」と呼ばれるスタイルは、サイト全体にわたって私が自ら選択して適用するものです。全サイトにわたるスタイルを大量に強制する自信がないため、このセクションは非常に小さく保つ必要があります。現時点ではこれら二つのみについて問題なく運用できていると感じており、
<section> 関連の設定については将来的に変える可能性があります:
/* 各 <section> の中央に幅 950px のカラムを配置 */ section { --inner-width: 950px; padding: 3rem max(1rem, (100% - var(--inner-width))/2); } a { color: var(--orange); }
ベーススタイルについては、「ボトムアップ」の方向で進めるのが最も扱いやすいと感じています。まずベーススタイルにほとんど何も記述せず、後にコンポーネントから共通パターンが見られるものをベーススタイルへ移行させるという方針です。
7. 間隔管理(Spacing)
パディングとマージンの管理方法についてはまだ完全には確立していませんが、Tailwind の時代とは明らかに意識を変えています。当時は、見た目だけで適当にどこかあちこちにパディングやマージンを散りばめるスタイルでしたが、現在はより原則に基づいたアプローチを意識しています。
現時点では、外側のレイアウトコンポーネントが間隔管理の主導権を握るように心がけています。例えば
<section> 内に子要素が多く配置され、それらの間にスペースを設けたい場合、以下の CSS で子要素間で均等なマージンを設定することができます:
section > *+* { margin-top: 1rem; }
参考のブログ記事:
- 「The owl selector(オウルセレクター)」
- 「No outer margin」
8. レスポンシブデザイン:グリッドを多用する!
Tailwind を使用してレスポンシブデザインを実現する際、私は多数のメディアクエリに依存していました。Tailwind は
md:text-xl のように、「md サイズ以上で text-xl スタイルを適用する」といった構文も提供します。
しかし今回は全く異なるアプローチを試しています。「あまり多くのブレイクポイントには頼らず、より柔軟な CSS グリッドレイアウトを作成する」ことです。これは難易度は高いですが、グリッド機能の可能性を探る上では極めて興味深い学習経験であり、Tailwind では実現できない素晴らしい例でもあります。
例えば、
auto-fit を使って大きな画面で自動的に 2 カラムに、小さな画面では 1 カラムを自動配置する方法を学んでいます:
display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 400px), max-content)); justify-content: center;
また、Tailwind では使えない素晴らしい機能として
grid-template-areas を頻繁に使用しています。参考のブログ記事:
- 「メディアクエリなしのレスポンシブグリッドレイアウト」 (CSS Tricks)
9. ビルドシステム:esbuild
開発環境上はビルドシステムが必要ありません。CSS には今や標準でインポート機能があり、以下のように記述できます:
@import "reset.css"; @import "typography.css"; @import "colors.css";
また、ネスト型セレクトルも標準搭載されており、以下のように記述できます:
.page { h2 { ...} }
必要であれば、esbuild を使って本番環境用の CSS ファイルにバンドルすることも可能です。そのコマンドは以下のようになります:
esbuild style.css --bundle --loader:.svg=dataurl --loader:.woff2=file --outfile=/tmp/out.css
一般的には CSS や JavaScript のビルドシステムを避ける傾向がありますが、esbuild(2021 年にここで紹介した)を使用することに全く構いません。その理由は、web 標準に基づいていることと、静的な Go バイナリであることが挙げられます。
なぜ Tailwind から離れることにしたのか?
数人の知人から「なぜ Tailwind をやめたのか」と聞かれました。いくつかの要因が絡み合いました:
- ビルドシステムへの依存度の高まり: 2018 年以降、Tailwind はビルドシステムに大きく依存するようになり、最新のバージョンを使用するにはビルドシステムなしでは不可能(?)になっているようです。そのため、長年にわたり Tailwind v2 を使用し続けてきました。(ちなみに
という軽量なツールも存在します)litewind - 巨大なファイルサイズ: 「Tailwind は常にビルドシステムと組み合わせるべき」ということは分かっていたものの、実際には組み合わせてこなかったので、多数のプロジェクトで 2.8MB の
ファイル(gzip で圧縮すると約 270KB)を抱えていました。これは少し滑稽に思えました。tailwind.min.css - CSS 技術力の向上: Tailwind を使い始めた頃より、現在の方が CSS にはるかに慣れています。結局のところ、Tailwind は限界があります。もし CSS に「変なことを(Weird Stuff)」したい場合、常に Tailwind で実現できるわけではありません。その制限が非常に役立つこともあります(このブログ記事の多くの部分は、これらの制限を再実装する内容です)が、現時点では自由に選択・判断したいと考えています。
- 混合運用の不具合: 結局のところ、バニラ CSS と Tailwind の両方を混在させたプロジェクトになってしまい、保守性に問題が生じました。
- HTML の意味性への興味: より意味のある HTML を書くことに対して好奇心を抱くようになりました。
学んだ新しい CSS 機能の知見
このプロセスを通じて、実際に使ってみても将来学びたいという興味深い CSS 機能を発見しました:
(「A Whole Cascade of Layers」参照)@layer@scope- Container queries(コンテナクエリ)
- Subgrid(サブグリッド)
Tailwind から離れる最終的な理由
この投稿では Tailwind を使って学んだことを多く語ってきましたが、それも真実です。しかし、3 年前の「Tailwind and the Femininity of CSS」という投稿を読んで心が深く動かされました。私は正直に言いますと、当初から CSS に対する態度がこの投稿で描写されているようなものを持っていた可能性が高いです:
「簡単にできると言われていて、だから簡単だと想像していたのに、実際に使ってみたら動かない。言語自体のせいだろう。だって自分は賢いし、これなら簡単だもの」
しかし過去 10 年間で、CSS という技術に対して愛と尊敬を学ぶことができました。そのため、数年前から「CSS は難しい」という批判に対し、CSS を軽視するのではなく、より上手に使い、この技術として真摯に取り組むことを決意しました。その姿勢の変化は私にとって全てが変わるほどの転換点でした。多くの frustrations(中心揃えができないなど)が、実は以前から CSS で解決できていることに気づいたのです。また「中心揃え」という概念自体が一義的ではなく、複数の方法があることが納得できるものです。「CSS は難しい」のは、それが難しい問題を解いているからに過ぎません!
過去 10〜15 年に実装された新しい CSS 機能(この投稿でもいくつか触れています)には非常に感銘を受け、それらが CSS を使いやすくしていることも実感しています。そして、自分の CSS スキル向上のための時間を割くことは、本当に素晴らしい経験でした。また、「Tailwind は CSS の専門性を貶めることに寄与している」と感じ、個人的には有益なツールであっても、その一部であることには同意したくなかったという思いを抱きました。特に LLM(大規模言語モデル)が普及する現在において、人間の専門性を尊重することはこれまで以上に重要になっています。
Tailwind を批判するもう一つのブログ記事:
「クラシックロック、マリオカート、そしてなぜ Tailwind で合意できないのか」
そのまま終わりに!
このサイトに関する全ての素敵な・楽しい部分は、元々 wizardzines.com のデザインと CSS を手がけた Melody Starling さんのおかげです。Melody さんに感謝します。
また、この作業を進める間には CSS Tricks や Smashing Magazine などから多くの素晴らしいブログ記事を読み、いくつかを本稿中にリンクさせていただきました。CSS コミュニティの方々が実践を共有してくださっていることに対し、深く感謝しています。