メドピア開発者ブログ

集合知により医療を再発明しようと邁進しているヘルステックリーディングカンパニーのエンジニアブログです。読者に有用な情報発信ができるよう心がけたいので応援のほどよろしくお願いします。

Tailwind CSSという風と共に走るフロントエンド開発

10km40分切りが2020年の目標、メドピア長距離部の小宮山です。

みなさんTailwind CSSはご存知でしょうか。tailwindとは「追い風」を意味します。最高に気持ちよく走れるコンディションですね。

目次

サービス概要

まずは今回新たに立ち上げたサービスの紹介です。 「MedPeerスポット×リクルートメディカルキャリア」という医師向けスポット求人マッチングサービス(以下、本サービス)が11月にリリースされました。

medpeer.co.jp

ログインや応募などサービスのコアな部分はMedPeer医師会員限定になってしまいますが、サイトの雰囲気自体は非会員でも十分に味わえますので是非ともサイトを開いてみてください。医師向けスポット求人という普段なかなか見ることができない世界を覗くこともできます。

技術概要

本サービスの技術的な構成をざっと紹介していきたいと思います。

まずはMedPeerといえば(?)なRuby on Rails(以下、Rails)です。最新ほやほやの6.0です。自分はフロントエンド畑な人間でそれほどRailsに精通しているわけでもなくそのすごさをちゃんとは理解していませんが、きっとすごいことなんだと思います。

以前のMedPeerなら、「Railsを使っています、以上です。」で終わってしまっていたところですが、なんと今回はもうひとつ目玉技術があります。Nuxt.js(以下、Nuxt)です。

ja.nuxtjs.org

実はNuxtの利用自体はMedPeerでは初めてではありませんでした。静的サイトのジェネレータとしてシンプルなLPを作成した実績はすでにあります。

かかりつけ薬局化支援サービス「kakari」のLPがまさにそれにあたります。

kakari.medpeer.jp

ではなぜ再度Nuxtを強調し直すのか。なんと今回は、Nuxtを本番運用してSSR(サーバーサイドレンダリング)するというMedPeer初の挑戦だったのです。さらにバックエンド(Rails)とフロントエンド(Nuxt)をリポジトリもAWSリソースも分離してしまうというMedPeer初だらけの野心的な技術構成となっていました。

そして非常に申し訳ないのですが、今回伝えたいのはNuxtのことでもフロントエンド分離のことでもありません。開発プロセスやVue.jsの話題ですらありません。それ以上にTailwind CSSのことを伝えたいモチベーションが高すぎました。新大陸の大地そのものよりも、そこに吹いていた追い風にこの心を掴まれてしまったのです。

Tailwind CSSとは何か

tailwindとはずばり「追い風」を意味します。今日の走りは絶好調だと思ったら折返しで現実に引き戻されるやつですね。

公式サイトの文言をここに引用します。

A utility-first CSS framework for rapidly building custom designs.

Tailwind CSS is a highly customizable, low-level CSS framework that gives you all of the building blocks you need to build bespoke designs without any annoying opinionated styles you have to fight to override.

一応CSSフレームワークという分類になりそうですが、BootstrapVuetifyといった所謂一般的なCSSフレームワークとはやや毛色が異なります。

一般的なCSSフレームワークの多くが「コンポーネント」を提供してくれるのに対して、Tailwind CSSが提供してくれるのはスタイルを便利に指定するためのツール類だけです。

例えばダイアログを作りたいと思ったとき、Vuetifyならコンポーネントとして既に用意されていますが、Tailwind CSSでは用意されたツールを組み合わせてダイアログというコンポーネントを自力で作らなければいけません。Tailwind CSSが提供してくれるのは自動車本体ではなく、その名前が意味する通り、自力で走る者たちへの追い風です。

HTMLとCSS

Webページを構成する3要素といえば、HTML・CSS・JavaScriptです。HTMLはWebページの構造を、CSSはレイアウトや装飾を、JavaScriptは何かをしてくれます。
(今回はJavaScriptについてはあまり掘り下げません。)

ja.wikipedia.org

文書の構造と体裁を分離させるという理念を実現する為に提唱されたスタイルシートの、具体的な仕様の一つ。

令和を生きる私はCSSが登場したころの状況を実際には知らないのですが、どうやらCSSはHTMLからスタイルを分離させることを目的に生み出されたもののようです。そして実際に、文章構造とスタイルやHTMLとCSSそれぞれに切り出して役割分担させるのがWebの作法だという認識が広く広まっていたと思います。

HTML

<ul class="content-list" >
  <li class="content-item">item 1</li>
  <li class="content-item">item 2</li>
</ul>

CSS

.content-list { display: flex; }
.content-item { padding: 1rem; }

なんの変哲もない例を出すとこんな感じでしょうか。HTML側ではタグにclassを付け、CSS側ではそのclassをセレクタとしてスタイルを付与しています。

一方でこんなHTMLはどうでしょうか。

HTML

<ul style="display: flex;" >
  <li style="padding: 1rem;">item 1</li>
  <li style="padding: 1rem;">item 2</li>
</ul>

スタイルをCSSに分離することなく、タグにそのまま書き込んでいます。所謂インラインスタイルです。基本的に、インラインスタイルが歓迎されることはほとんどないと思われます。実際に私もこのコードだけを見たらレビューコメントを入れる手を止めることはできないでしょう。

しかしなぜ歓迎されないのでしょうか?実のところ「そういうもの」で終わらせてしまうことが多く、あまり深く考えたことはありませんでした。実際にCSSは誕生目的からして「そういうもの」なのですが、改めてその問題点をざっと考えてみました。

  • HTMLが冗長になる
    class指定が不要とはいえ、styleで書き込むので文字数の絶対量は増えてしまいます。
  • スタイルの共通化ができない
    タグ毎にstyleを書き込むしか無いので、リストアイテムなどには大量に同じstyle属性を書き込まないといけません。HTML冗長化をさらに後押しします。
  • CSS関連のエコシステム(Sass、PostCSS、Stylelintなど)が使えない
    最近のフロントエンド開発ではこれが相当のデメリットではないでしょうか。
    (もしかしたらインラインスタイルにもいい感じに変換やlintを当ててくれる仕組みがあるかもしれません。)
  • レスポンシブ対応が難しい
    若干思いつきベースですが、インラインスタイルでレスポンシブなスタイルって作れるんでしょうか?やるなら下記のようになりそうですが、試そうと思ったこともなさすぎて効くのかどうかは未検証です。
<ul style="@media (min-width:480px) { display: flex; }"> ... </ul>

HTMLとCSSとコンポーネント

時代は変わりつつあります。既に変わってしまっているのかもしれません。その変化の主役となる存在がコンポーネントです。HTMLとCSSは文章構造とスタイルという役割で分離するのが当たり前だったのに、コンポーネントという新たな区切がより重視されるようになってきています。

従来のWebページ構成イメージ
従来のWebページ構成

コンポーネント指向なWebページ構成その1のイメージ
コンポーネント指向なWebページ構成その1

コンポーネント指向がもたらす大きなメリットは、コンポーネントという明確な区切りが生まれることです。今までのHTML・CSS・JavaScriptという3層では、互いに分離されてはいるものの、その層内はほぼグローバル空間と化していました。良く言えば自由で手軽に作れてすぐに変更可能、悪く言えば分かりにくく壊れやすくて変化に弱い。

コンポーネントという区切りは、この3層のより上位の区切りとしてWebページのグローバル空間を分割します。そしてさらにコンポーネント内でHTML・CSS・JavaScriptの3層が存在するようなイメージです。

双方ともにメリットとデメリットは様々にありますが、今のフロントエンド界隈はコンポーネント指向が勢い付いていると見て間違いないでしょう。

シンプルに考えると、Webページがコンポーネントによってまず区切られ、コンポーネント内部では従来の3層区切りがそのまま再現されているだけです。確かにコンポーネントが注目されだした当初はそうだったかもしれません。

しかし変化はそこで留まってはくれませんでした。コンポーネントという閉じた安全な世界が作られたことで、その内部ではかつて常識と考えられていた壁の存在感が薄れだしました。

コンポーネント指向なWebページ構成その2のイメージ
コンポーネント指向なWebページ構成その2

コンポーネントとして完結していて、外部との連携で求められるインタフェースが満たされてさえいれば、コンポーネント内部の実装が多少暴れん坊になっていても大した問題にはなりません。いや問題ではあるんですが、コンポーネント内部はいわばprivateな部分なので大した問題ではないことがほとんどです。コンポーネントという区切りが明確に存在しているので、どうしようもなくなったら丸ごと取り替えてしまうことだって可能です。

かくしてコンポーネントの躍進により、HTMLとCSSの境界は薄れだしました。もちろん完全になくなったわけではありませんが、CSSが生まれた目的そのものであったHTMLとスタイルの分離は、コンポーネントというより大きな関心事にかき消されつつあります。

コンポーネントと雑なセレクタ

コンポーネントという概念によってHTMLとCSSの間にあった従来の区切りは曖昧になり、両者の距離はぐっと近づいています。区分けされた両者を繋ぐために必須だったclassを軽視する、こんな手抜きスタイル指定も横行しているのではないでしょうか。

HTML

<ul class="content-list" >
  <li>item 1</li>
  <li>item 2</li>
</ul>

CSS

.content-list { display: flex; }
.content-list > li { padding: 1rem; }

階層を指定しているとはいえ、セレクタとしてliを直で指定しています。従来のHTML・CSS分離の方針に従うなら真っ先にレビュー指摘が入りそうなコードです。実際に私もこんなコードを素の状況で見つけたらおそらく指摘を入れます。ただしこのコードがコンポーネントに関するものであれば話は別で、CSSにHTMLの構造が漏れ出していてもそれほど気にしません。

理由は2つあります。1つはスタイルがコンポーネント内に閉じているからです。liという豪快なセレクタ指定がされていようと、そのセレクタがコンポーネント内のHTMLに限定されているのなら、コンポーネント外の予期せぬ箇所でスタイルが崩れることはありません。
(セレクタのパフォーマンス観点については今回は立ち入りません。)

もう1つは、classを丁寧に付けるほうがむしろコストが高くなるかもしれないからです。classを増やせば当然HTMLの文字数は増えて汚れます。適切なclass名を文書構造と翻訳サイトを往復しながら考えなくてはなりません。HTMLとCSS間の視点移動だって必要です。つまり面倒くさいのです。単発では小さな手間かもしれませんが、それを数百数千回と繰り返すのはとても面倒くさいのです。人生は短いんです。早く家に帰って走りたいんです。

コンポーネントとインラインスタイル

コンポーネントという箱庭の存在によって、雑なセレクタが許されるようになってきたとしましょう。エンジニアというのはどこまでも怠惰を求める生き物らしいです。当然、一度雑になったセレクタ指定はどこまでも雑になっていきます。雑になればなるほどHTMLとCSSは近づいていきます。そして行き着く先に何があるかというと、インラインスタイルの再登場です。

HTML

<ul style="display: flex;" >
  <li style="padding: 1rem;">item 1</li>
  <li style="padding: 1rem;">item 2</li>
</ul>

コンポーネント指向という前提に立ち、改めて先に挙げたインラインスタイルのデメリットを再評価してみます。

  • HTMLが冗長になる
    基本的には従来と同様だと思います。
  • スタイルの共通化ができない
    コンポーネント単位での共通化という大きな道が開けます。利用するフレームワーク依存となりますが、v-forjsxなどで効率的に記述する手段も多くあります。
  • CSS関連のエコシステム(Sass、PostCSS、Stylelintなど)が使えない
    基本的には従来と同様だと思います。
  • レスポンシブ対応が難しい
    コンポーネントごと表示を切り替えるなどの手段が生まれてきそうですが、ほぼ従来と同様と思われます。

ただしHTMLの冗長さやCSSエコシステムについては、コンポーネント指向な開発の現場でよく使われるstyled-componentsやCSS in JSなどのJavaScript側からのアプローチによって解決は可能かもしれません。
(普段Vue.jsのscoped CSSばかり使っているのでこのあたりの動向には疎いです。)

場面によってはインラインスタイルで済ませてしまうことも十分に可能ですが、大勢をそれだけでなんとかするのはやはり厳しい印象です。特にCSS系のエコシステムとの相性と、レスポンシブ対応のやりにくさは致命的です。インラインでベンダープレフィックスを付けていく作業以上の苦痛はなかなか見つからないと思います。人生は短いし早く帰って走りたいんです。

Tailwind CSSがもたらしたもの

やっとTailwind CSSの話題にたどり着きました。先に挙げたインラインスタイルの例をTailwind CSSで書くとこうなります。

HTML

<ul class="flex" >
  <li class="p-4">item 1</li>
  <li class="p-4">item 2</li>
</ul>

ご理解いただけたでしょうか。ここまで長々と紹介してきたコンポーネントとスタイル指定に関する内容そのものが、Tailwind CSSの良さへと至る道筋です。コンポーネント化の波がもたらしたスタイル指定の怠惰の極みにあるインラインスタイル、良さもあるが辛さも多量に含んだその地点に到達する一歩手前に我々を留めてくれる存在、それこそがTailwind CSSです。

見ての通り、Tailwind CSSはスタイルとほぼ1対1に対応したclassを提供してくれます(一部複合的なスタイル付きclassがあったり、独自で拡張することも可能です)。つまり実質class方式でスタイルを指定しているだけなので、autoprefixerpurgecssなどとの連携が容易です。

ブレークポイント用のプレフィックス(sm:, md:, lg:)が用意されているので、レスポンシブ対応に苦慮する必要もありません。

例えばPCサイズ以上でだけ横並びにしたい場合はこう書けます。インラインスタイルの良さを残しつつ悪さを緩和する、絶妙な具合ではないでしょうか。

HTML

<ul class="flex flex-col md:flex-row" >
  <li class="p-4">item 1</li>
  <li class="p-4">item 2</li>
</ul>

HTMLが冗長になるという点に関しては、インラインスタイルよりは改善されているものの、class形式でスタイルを当てていくときほどには軽量にならないです。スタイルとclassがほぼ1対1になっているので、この点は受け入れるしかないというのが現時点の評価です。

まとめ

Tailwind CSSは決して強力なCSSフレームワークではありません。フレームワークと呼んで良いのか怪しいくらいに具体的なものは何も提供してくれません。公式サイトに掲げられている通り、utility-firstなツールを提供してくれるだけです。ツールをどう使うか、何を作るかは完全に使い手に委ねられています。

そこに心地よさを感じかどうか個々人で評価が分かれるかもしれません。しかしながら本サービスの立ち上げからリリースまでTailwind CSSを使い続けた私の感想としては、「次もまた使いたい」し「発展に貢献したい」です。

その理由を端的に表現するのはとても難しいです。なぜなら具体的にこれが良いと言い切れるようなものではなく、この記事で述べてきたように、Webフロントエンドの潮流の中で味わう様々な要因が組み合わさって到達した良さだからです。しかしその良さを実感しているのは事実です。

今回はTailwind CSSの使い方自体はほとんど紹介できませんでしたが、最近は利用事例も増えて情報も多く出ているので探すのに困ることはないと思います。需要があればMedPeerでのTailwind CSS利用事例として改めて記事化するかもしれません。

Tailwind CSSの巻き起こす追い風、みなさんも是非味わってみてください。


(☝︎ ՞ਊ ՞)☝︎是非読者になってください


メドピアでは一緒に働く仲間を募集しています。 ご応募をお待ちしております!

■募集ポジションはこちら

https://medpeer.co.jp/recruit/entry/

■開発環境はこちら

https://medpeer.co.jp/recruit/workplace/development.html