【CSS】BEMにTailwindは「混ぜるな危険」かも、、？

## どうしていたか

CSSの実装をBEMベースで行っていたプロジェクトに部分的なTailwindを採用したところ、ちょっとうまくいかなかったというお話です。
そのプロジェクトでは以下のように共存させていました
- BEMを用いてコンポーネント単位でスタイルを閉じ込める
- そのコンポーネントの外側のレイアウト（配置、余白、幅など）について、Tailwindを使用する

**BEMがベースにあって、部分的にTailwindを使用している**という感じです。

レイアウトやちょっとした余白を付けるためのクラス名を考えることは、地味に頭のリソースを使ってしまうので、それを避けたいという意図がありました。

## 実装イメージ

たとえばコンポーネントAとBをBEMで実装し、それをTailwindで配置すると、HTMLはだいたいこんな感じになります。
```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`のような、コンポーネントを配置するためだけのクラス名を付けてコンポーネントの配置を決める必要がでてきます。
```html
<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で実装すること
    - 横並び
    - マージン
    - 配置
    - 幅など
:::note info
コンポーネント単位に幅やマージをきめないことは、汎用性を上げるためのBEMのテクニックです。
[https://qiita.com/Takuan_Oishii/items/0f0d2c5dc33a9b2d9cb1#blockにはmarginを指定しない](https://qiita.com/Takuan_Oishii/items/0f0d2c5dc33a9b2d9cb1#block%E3%81%AB%E3%81%AFmargin%E3%82%92%E6%8C%87%E5%AE%9A%E3%81%97%E3%81%AA%E3%81%84)
:::

## その結果、開発ははかどったか

最初はよかったのですが、実装者が二人、三人と増えだした頃にレビューの負担が増していることに気が付きました。
レビューで指摘されたことは**BEMで実装するか、Tailwindで実装するか、さじ加減が難しい**という問題です。
そのため認識合わせの説明やルールの拡充に足止めを食らってしまいました。

## Tailwindはユーティリティファーストである

そもそもTailwindの方針とずれた使い方をしてしまっていたことが悪かったようです。
Tailwindを利用することでHTMLがやや読みづらくなる半面、以下のようなメリットがあります

- クラス名を考えなくてよい
- HTMLファイルのみで完結
- CSSの影響範囲が明確になる

手順としては

1. まずTailwindのユーティリティクラスで実装
2. 再現できない部分はカスタムクラスを実装
3. 繰り返しになったタイミングでコンポーネント化

これがTailwindのコアコンセプトであるユーティリティファーストなアプローチです。

https://tailwindcss.com/docs/utility-first

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

こちらの記事にある**Tailwindはエンジニアライク、BEMはWeb制作者ライク**というのが妙にしっくりきました。

https://qiita.com/mu_tomoya/items/14cd7c7ca4c6d1af96ca#tailwindcss%E3%81%8B%E3%82%89%E6%99%AE%E9%80%9A%E3%81%AEcss%E3%81%B8

> それまではTailwindCSSのユーティリティクラスを組み合わせて作成した、エンジニアライクなCSSでしたが、Web制作者ライクな.attention-item__linkのようなクラス名にスタイルをあてるようなBEM設計になりました。
> 

## 結局どうしたか

BEM+Tailwindをやめて、BEMのみに戻しました。
レビューのやり取りを通して、Tailwindを使用するならユーティリティファーストの考え方にあわせて全体的にTailwind化すべきと考えましたが、プロジェクトの途中からTailwindに変更することのコストがおおきいためです。

## 終わりに

結果的に今回の件では2つの対応を比較できました。

- BEMベースで部分的にTailwindを使用するのか（BEMにかぎらず任意のCSS設計と合わせた場合）
- Tailwindベースでカスタムクラスを使用するのか

前者はルール化が難しく、レビューコストが大きくなる場合があることが分かりました。
やはりTailwindを採用するのであれば、本来のユーティリティファーストなアプローチである後者を採用したほうがよさそうですね。
もしTailwindに他のCSS設計を混ぜようと考えている方がいれば、**混ぜるな危険**なところもあるよ、という参考になれば幸いです。