概要
原著者の許諾を得て翻訳・公開いたします。
- 英語記事: The zen of Just Writing CSS
- 公開日: 2017/09/06
- 著者: Rich Harris
- サイト: https://svelte.technology/
SFCについてはVue.js: 単一ファイルコンポーネントもどうぞ。
CSSを迷いなく書く極意: 単一ファイルコンポーネント(翻訳)
これは未来の話だが、私たちは既にそれを実践しているのだ。
CSSを嫌うのが流行っています。CSSを嫌う理由はいくらでもありえますが、突き詰めれば「CSSが予測不可能である」ということです。スタイルのルールをこねくり回しているうちに、まったく関係ない別のレイアウトが不意に壊れてしまう(しかもたいてい納品間近に起きる)という経験をしたことがない人がいるとすれば、新人か、さもなければよほどプログラミングが上手いかのどちらかでしょう。
JavaScriptコミュニティはこの問題に取り組み続けてきました。ここ数年もの間、CSSがちゃんと振る舞うようにするための「CSS-in-JS」(CIJ)と呼ばれるライブラリが、カンブリア爆発のごとく大量に出現しました。
もしかすると誰も気づいてないのかもしれませんが、CSS-in-JSを使わなくてもCSSの大きな問題はすべて解決できるのです。これらの問題が片付きさえすれば、CSSを書く苦痛がなくなるだけでなく、むしろ書くのが楽しくなります。それに、CSS-in-JSを導入したために新たに起こる問題の解決方法を探して回る必要もありません。
この記事は、CSS-in-JSコミュニティの苦心の成果を批判するつもりはまったくありませんのでご了承ください。CSS-in-JSコミュニティは非常に活動のさかんなJSエコシステムであり、毎週のように新しいアイデアが生まれています。本記事の意図は、CSS-in-JS以外のアプローチ、つまり現実のCSSを使った単一ファイルコンポーネントに基づくアプローチの素晴らしさを示すことです。
CSSの最大の問題
CSSの中では、あらゆるものがグローバルです。それが原因で、ごく小さなマークアップに適用するつもりだったスタイルがしばしば他の部分にまで適用されてしまいます。それが原因で、開発者が最後の手段としてそこらで見つけてきた名前空間の命名慣習(強制は困難なので「ルール」とは呼べません)に頼らざるを得なくなることがしばしばあり、しかもその命名慣習は多くの場合RSIのリスクを増やすだけに終わってしまいがちです。
チームで作業しているとさらに深刻です。他の人が作ったスタイルは、意図もマークアップがどこに適用されるかもわかりにくく、それを外すとどんな災いが起きるか読めないことが多いので、あえて手を加えようとする人はいないでしょう。
これらすべてが原因で、スタイルシートはひたすら追加を繰り返すだけの代物になってしまいます。どのコードなら安全に削除できるのかを知る方法がないため、既存のスタイルを別のもっと詳細なスタイルで打ち消すことがかなり小さなプロジェクトですら当たり前になっています。
SFCがすべてを変える
SFC(単一ファイルコンポーネント: Single File Components)の基本アイデアは「1つのHTMLファイルに独自のコンポーネントを書き、スタイルや振舞いを記述する<style>
属性や<script>
属性を必要に応じてコンポーネントに含める」というシンプルなものです。Svelte、Ractive、Vue.js、Polymerはどれもこの基本パターンに従っています。
本記事では以後Svelteを使いますが、テンプレート言語を使うのがためらわれる方はVue.jsをお使いください。Vue.jsはSFCでJSXを使えます。テンプレート言語については心配無用とだけ申し上げておきますが、これはまた別のトピックとなります。
SFCを使うことで以下のような素晴らしい結果を得られます。
- スタイルのスコープがそのコンポーネントに限定される: 他のコンポーネントに影響することもなければ、カスケードが予測不可能になることもありません。クラス名を恐ろしく長くしてコンフリクトを避ける設計も不要です(訳注: これはBEMなどを指しているようです)。
- フォルダ構造をさんざん探した挙句、画面を壊すようなスタイルを見つけ出すことがなくなる
- コンパイラ(Svelteの場合)は不要なスタイルを見つけて削除できる: 追加しかできないようなスタイルシートとおさらばできます。
実際の方法を以下の動画でご覧ください。
動画: https://svelte-technology-assets.surge.sh/just-write-css.mp4
コードエディタはCSSを理解できるので、オートコンプリート、Lint、シンタックスハイライトといった機能をすべて使えますし、こちらを消耗させるJS注入ツールも一切不要です。
しかもこれはキャメルケースをあちこちの引用符に紛れ込ませるどこかのまがい物と違う「本物のCSS」なので、開発ツール上で細かく調整してからソースコードに貼り直すというワークフローが使えます。私はもうこれなしではもう生きていけません。さらに、CSSで探している行を(エディタの)ソースマップで即座に見つけられます。これがどれほど重要であるか、いくら強調してもよいくらいです。WYSIWYGモードで作業していてもコンポーネントのツリーを気にかける必要がないので、スタイルを決めているのがどのコードかを確実に特定できます。そのコンポーネントを作成したのが他のメンバーであればなおさらです(私はこれこそがCSSワークフローの生産性を向上する唯一にして最大の方法であると断言します。私もかつてそうでしたが、今やソースマップ機能なしでCSSを書くのは本当に時間のムダです)。
Svelteはセレクタを変換することでスコープを実現します(そのために該当の要素にも適用される属性を1つ使いますが、正確な仕組みは重要ではなく、今後変わるかもしれません)。未使用のルールを見つけると警告して削除し、続いて結果を最小化して.cssファイルに書き出せる形にします。他にも、Webコンポーネントにコンパイルする新しい実験的オプションもあり、お望みならShadow DOMを用いてスタイルをカプセル化できます。
これらをすべて実現できるのは、CSSがcsstreeで解析され、自分のマークアップのコンテキスト内で統計的に分析されるからです。統計的分析によって、スマート最適化やa11y(accessibility)ヒントといった素晴らしい可能性への扉が一斉に開かれました。スタイルが実行時に動的に算出されていたらこうはいきません。これはまだ始まったばかりなのです。
「それ、このツール追加すればできるよ」について
先の動画を見て「なかなかいいね、でも自分たちはTypeScriptにするよ。エディタごとにプラグインを書けばオートコンプリートやシンタックスハイライトもできるようになるし」といった感想をお持ちの方、つまりCSSの一貫性を実現するためにコードやドキュメントをどっさり書いてチーム内で普及に努め、サブプロジェクトを山ほどメンテすることになっても一向に構わないという方は、残念ながら私と意見が合わないということになります。
まだすべての解を得られたわけではない
既に申し上げたように、CSS-in-JSは長年続く疑問のいくつかについて答えを示しています。
- npmでスタイルをどうやってインストールするか
- 1か所で定義された定数をどうやって再利用するか
- 宣言をどうやって組み立てるか
個人的には、これらの問題があっても、先に示したアプローチから得られるメリットは帳消しにならないと考えます。優先順位は人それぞれ違うので、十分な理由があればCSSを捨てる人がいるかもしれません。
しかし最終的には、CSSの理解は避けて通れません。CSSが好きであろうと嫌いであろうと、CSSを学ばなければなりません。Webメンテナーにとっての選択肢は2つあります。何らかの抽象化を行って、Web開発の学習曲線を急上昇させる方法を選ぶか、皆で力を合わせてCSSの良くない点を修正するかです。私はもうどちらにするか決めています。