👏

だから僕はtailwind cssを使いたくない。tailwindのしんどいところとemotionとの比較

2023/05/24に公開
4

どうもこんにちは。
最近TLでtailwind cssのお気持ち表明をよく見るなあと思ったので(もう何万回も他の人がしているけど)僕もtailwind cssのお気持ち表明をしたいと思います。
深夜テンションで書いているので文章は適当です。
ぶっちゃけtailwind cssはtailwind推進派の皆様と比べると知見量は確実に劣るので、こうやったら解決できるよ等ありましたら教えていただきたいです。
また、自分は主にReact/Nextを使用しますのでその目線で書かれています。

お願い

一通り試すことで知識を深め、忘れないために個人的なメモとしてアウトプットしていますので、英語の解釈が間違っていたり、おかしいことを言ってるかもしれないです。

もし間違ってることを言っていたらコメントで教えていただけると非常に助かります。

tailwindのしんどいところ

※今回説明するにあたって、tailwindcomponentsの以下のコンポーネントのソースコードをお借りしてます。
https://tailwindcomponents.com/component/notification-modal-with-tailwind-css

ズラーと横一列に並んだ大量のクラス

<div class="fixed left-0 top-0 flex h-full w-full items-center justify-center bg-black bg-opacity-50 py-10">

参考コンポーネントの一行目です。はい笑 もうしんどいですね。zennでも横スクロールしないと見れないですし、もちろんPrettierでも改行されないのでVSCodeでも一行で大変見にくいです。
これが大量に並んでるソースコードとかゾッとします。
ちなみにこれをemotion/reactで書き直すと以下のようになります。(chatgptに書き直してもらいました)

const styles = css`
  position: fixed;
  left: 0;
  top: 0;
  display: flex;
  height: 100%;
  width: 100%;
  align-items: center;
  justify-content: center;
  background-color: rgba(0, 0, 0, 0.5);
  padding-top: 10px;
`;

見やすい!!!!!!!!!!

これを各要素ごと一対一で書いていって、別ファイルに切り出してコンポーネント内に閉じ込めれば大変見やすくなります。
やってることはtailwindと変わらないでしょ? なんでわざわざ見にくいことするんだろう...

擬似要素が増えるとさらにしんどくなる

beforeやafterなどの擬似要素が増えるとさらにしんどくなります。chatgptに適当なbeforeをつけてもらいましょう。

<div class="fixed left-0 top-0 flex h-full w-full items-center justify-center bg-black bg-opacity-50 py-10 before:absolute before:top-1/2 before:left-1/2 before:-translate-x-1/2 before:-translate-y-1/2 before:w-72 before:h-72 before:bg-red-500 before:rounded-full before:shadow-lg before:z-[-1]">

もうわけがわからないですね。このコードが出てきたらそっと閉じると思います。
ちなみにこれをemotion/reactで書き直すと以下のようになります。(chatgptに書き直してもらいました)


const styles = css`
  position: fixed;
  left: 0;
  top: 0;
  display: flex;
  height: 100%;
  width: 100%;
  align-items: center;
  justify-content: center;
  background-color: rgba(0, 0, 0, 0.5);
  padding-top: 10px;
  overflow: hidden;

  &::before {
    content: '';
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 200px;
    height: 200px;
    background-color: red;
    border-radius: 50%;
    box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
    z-index: -1;
  }
`;

(tailwindよりは)見やすい!!!!!!!!!!
改善の余地はありますが、どう考えてもtailwindより見やすいです。

レスポンシブ対応するともっともっとしんどい

<div className="fixed left-0 top-0 flex h-full w-full items-center justify-center bg-black bg-opacity-50 py-10 before:absolute before:top-1/2 before:left-1/2 before:-translate-x-1/2 before:-translate-y-1/2 before:w-72 before:h-72 before:bg-red-500 before:rounded-full before:shadow-lg before:z-[-1] sm:py-20 sm:before:w-96 sm:before:h-96">

先ほどのものにスマホのレスポンシブ対応をしてもらいました。もう見たくありません。
これに、タブレット対応や複雑な画面幅でのレスポンシブ対応が入ったらもう逃げ出す自信があります。

じゃあどうするのか

流石に、こんなコードを書く人はいません。
tailwindでは@applyで共通化して短くするらしいです。
でもそれってtailwindの良さ消え去ってただ見にくくにしただけじゃない?
というかそれするならemotionでいいじゃん。

動的にcssを変えるのがしんどい

React/Nextを書く人ならわかると思いますが、結構cssを動的に変えたいことって多いと思います。
でも、tailwindは動的に変える時にクラス名を直接与えてあげないといけないのでしんどいです。

// NG例
const n = 4
<div className={`w-${n} h-${n}`}></div>

// OK例
const widthSize = "w-4 h-4"
<div className={`${widthSize}`}></div>

でも、emotionならこうやって書けちゃいます。

const styles = css`
  width: ${w}px;
  height: ${w}px;
`;

やっぱり毎回クラス名を直接与えるのは直感的じゃないですし、しんどいです。
もしかしたら最新バージョンではこうやる必要はないかもですが...

まとめ

こうやって書いててやっぱり一番使いたくない理由はJSXが汚くなるからに尽きるなと思いました。
加えてPrettierでも改行されない点もかなり大きいと感じました。
また、layerがあるといえど@applyを多用すると、大規模になればなるほどしっかり設計しないといつか必ず負債化すると思いました。
結局@applyを使用してクラス名を共通化して短縮してemotionの良いところを潰すのであれば大人しくCSSinJSを使ったほうがいいんじゃないかなと思います。

結論として、レスポンシブ対応も必要ないような小規模な個人開発レベルであればtailwindでも問題ないと思いますが、業務システムなどの大規模なものではtailwindは採用してほしくないです。
CSSinJSを要素に一対一にしてコンポーネントごと閉じた方が一番負債化せず見やすいと思います。

Discussion

Kazu1Kazu1

大変同意する内容で勉強になります。
個人開発などで自分で把握できる場合はtailwindcssは良いかも知れませんが、可読性が求められるチーム開発だと微妙なんじゃないかなあと思いました。

kage1020kage1020

これを各要素ごと一対一で書いていって、別ファイルに切り出してコンポーネント内に閉じ込めれば

私はこれが嫌でTailwindを使いたくなります。複数ファイルを言ったり来たり、クラス名考えたり、スクロールしまくったり。

確かに1行辺りの文字数が増えて見づらくなるのは問題ですが、エディタが折り返してくれれば幾分かマシです。また、うまくコンポーネント分割すれば、そのようなコードは末端だけになりあまり気にならないと感じます。

動的にcssを変えるのがしんどい

これに関しては完全に同意です。私は諦めてstate依存でクラスを切り替えてます。

https://tailwindcss.com/docs/content-configuration#dynamic-class-names

elpntelpnt

流石に、こんなコードを書く人はいません。
tailwindでは@applyで共通化して短くするらしいです。

これは公式が「やるな」と言っているアンチパターンです。ドキュメントを読む限りこのようなディレクティブが用意されている意図としては、既に他のCSSライブラリがクラス名を当てたコンポーネントのスタイルを一時的に Tailwind CSS のデザイントークンで置き換えるためのものだと思っています。少なくとも一から始めたプロジェクトに Tailwind を導入する際はクラス名が短くなるからという理由で @apply を使用するのは避けたほうがよさそうです。

// 他ライブラリのコンポーネント
<Button variant="primary">Open</Button>

// 出力された HTML
<button class="primary_button">Open</button>

// CSS
.primary_button {
  @apply rounded p-2 bg-indigo-500; // Tailwind のもので置き換える
}

動的にcssを変えるのがしんどい

こちらに関してはむしろそういう(動的にCSSを変えてはいけないという)強い意図を持ってこのような設計になっています。公式ドキュメントにはそのような記載は見つけられなかったのですが、Tailwind Labs が有料で公開している Refactoring UI では、1px単位でデザインにこだわり出すと開発スピードが遅れる・結局はデザインも一貫性が無くなってしまうという理由で、事前に決めたサイズだけを使うことを推奨しています。そういうわけで

やっぱり毎回クラス名を直接与えるのは直感的じゃないですし、しんどいです。
もしかしたら最新バージョンではこうやる必要はないかもですが...

の部分に関しては将来的にも実現しないのではないかと思っています。v2.1 で JIT モードが導入されコンパイル時に p-[22px] のように任意値を生成できるようになった際も、デザインシステムを破壊する一因になるとしてコミュニティから批判も集まったと記憶しています。実際 eslint-plugin-tailwindcss にはこの機能を制限する設定も用意されています

mu_tomoyamu_tomoya

そもそも、TailwindCSSであろうとemotionであろうと、ひとつのclassやタグにに何でもかんでもCSS書き込んだら見づらくないですか?