どうしていたか
CSSの実装をBEMベースで行っていたプロジェクトに部分的なTailwindを採用したところ、ちょっとうまくいかなかったというお話です。
そのプロジェクトでは以下のように共存させていました
- BEMを用いてコンポーネント単位でスタイルを閉じ込める
- そのコンポーネントの外側のレイアウト(配置、余白、幅など)について、Tailwindを使用する
BEMがベースにあって、部分的にTailwindを使用しているという感じです。
レイアウトやちょっとした余白を付けるためのクラス名を考えることは、地味に頭のリソースを使ってしまうので、それを避けたいという意図がありました。
実装イメージ
たとえばコンポーネントAとBをBEMで実装し、それをTailwindで配置すると、HTMLはだいたいこんな感じになります。
<!-- Tailwindで横並びのレイアウトに -->
<div class="flex gap-[10px]">
<!-- component-aとcomponent-bはBEMで実装 -->
<div class="component-a width-[100px]"><!-- Tailwindでcomponent-aのみ幅を調整 -->
<h2 class="component-a__title"></h2>
<p class="component-a__text"></p>
</div>
<div class="component-b">
<h2 class="component-b__title"></h2>
<p class="component-b__text"></p>
</div>
</div>
Tailwindのおかげで横並びやマージンのためにわざわざクラス名を考えることなく、簡単にレイアウトができます。
もしTailwindを使用しない場合、たとえば上記のコンポーネントがAboutページにあるとしたら、about-page__flex
やabout-page__component-a
のような、コンポーネントを配置するためだけのクラス名を付けてコンポーネントの配置を決める必要がでてきます。
<div class="about-page">
<!-- about-page__flexで横並びのレイアウトに -->
<div class="about-page__flex">
<!-- component-aとcomponent-bはBEMで実装 -->
<!-- about-page__component-aでcomponent-aのみ幅を調整 -->
<div class="component-a about-page__component-a">
<h2 class="component-a__title"></h2>
<p class="component-a__text"></p>
</div>
<div class="component-b">
<h2 class="component-b__title"></h2>
<p class="component-b__text"></p>
</div>
</div>
</div>
※CSSファイルは別にあるとします
※ページ単位を親ブロックとしましたが粒度はプロジェクトによります
.about-page__flex {
display: flex;
gap: 10px;
}
.about-page__component-a {
width: 100px;
}
このようにレイアウトやちょっとした余白を付けるためのabout-page__flex
やabout-page__component-a
のようなクラス名を考えることは、地味に頭のリソースを使ってしまいます。
あぁTailwind楽だな~と感じました。
しかしTailwindをむやみやたらと使用するとHTMLの可読性が下がってしまいます。そこで以下のようなルールをREADMEに記載しました。
- 見た目上コンポーネントと判断できるものはBEMで実装すること
- コンポーネントの外側のレイアウトはTailwindで実装すること
- 横並び
- マージン
- 配置
- 幅など
コンポーネント単位に幅やマージをきめないことは、汎用性を上げるためのBEMのテクニックです。
https://qiita.com/Takuan_Oishii/items/0f0d2c5dc33a9b2d9cb1#blockにはmarginを指定しない
その結果、開発ははかどったか
最初はよかったのですが、実装者が二人、三人と増えだした頃にレビューの負担が増していることに気が付きました。
レビューで指摘されたことはBEMで実装するか、Tailwindで実装するか、さじ加減が難しいという問題です。
そのため認識合わせの説明やルールの拡充に足止めを食らってしまいました。
Tailwindはユーティリティファーストである
そもそもTailwindの方針とずれた使い方をしてしまっていたことが悪かったようです。
Tailwindを利用することでHTMLがやや読みづらくなる半面、以下のようなメリットがあります
- クラス名を考えなくてよい
- HTMLファイルのみで完結
- CSSの影響範囲が明確になる
手順としては
- まずTailwindのユーティリティクラスで実装
- 再現できない部分はカスタムクラスを実装
- 繰り返しになったタイミングでコンポーネント化
これがTailwindのコアコンセプトであるユーティリティファーストなアプローチです。
こちらの記事にあるTailwindはエンジニアライク、BEMはWeb制作者ライクというのが妙にしっくりきました。
それまではTailwindCSSのユーティリティクラスを組み合わせて作成した、エンジニアライクなCSSでしたが、Web制作者ライクな.attention-item__linkのようなクラス名にスタイルをあてるようなBEM設計になりました。
結局どうしたか
BEM+Tailwindをやめて、BEMのみに戻しました。
レビューのやり取りを通して、Tailwindを使用するならユーティリティファーストの考え方にあわせて全体的にTailwind化すべきと考えましたが、プロジェクトの途中からTailwindに変更することのコストがおおきいためです。
終わりに
結果的に今回の件では2つの対応を比較できました。
- BEMベースで部分的にTailwindを使用するのか(BEMにかぎらず任意のCSS設計と合わせた場合)
- Tailwindベースでカスタムクラスを使用するのか
前者はルール化が難しく、レビューコストが大きくなる場合があることが分かりました。
やはりTailwindを採用するのであれば、本来のユーティリティファーストなアプローチである後者を採用したほうがよさそうですね。
もしTailwindに他のCSS設計を混ぜようと考えている方がいれば、混ぜるな危険なところもあるよ、という参考になれば幸いです。