CSSを迷いなく書く極意: 単一ファイルコンポーネント(翻訳)

概要

原著者の許諾を得て翻訳・公開いたします。

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>属性を必要に応じてコンポーネントに含める」というシンプルなものです。SvelteRactiveVue.jsPolymerはどれもこの基本パターンに従っています。

原注: Svelteが初めての方はこちらの紹介記事推薦ツイートをご覧ください。

本記事では以後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の良くない点を修正するかです。私はもうどちらにするか決めています。

関連記事

新版: やばい臭いのするCSSコード(翻訳)

Webデザイナーがこっそり教える4つのテクニック

CSS/JS: 画像を不規則な形に切り取ってテープで貼り付けるテクニック(翻訳)

Ruby on RailsによるWEBシステム開発、Android/iPhoneアプリ開発、電子書籍配信のことならお任せください この記事を書いた人と働こう! Ruby on Rails の開発なら実績豊富なBPS

この記事の著者

hachi8833

Twitter: @hachi8833、GitHub: @hachi8833 コボラー、ITコンサル、ローカライズ業界、Rails開発を経てTechRachoの編集・記事作成を担当。 これまでにRuby on Rails チュートリアル第2版の半分ほど、Railsガイドの初期翻訳ではほぼすべてを翻訳。その後も折に触れてそれぞれ一部を翻訳。 かと思うと、正規表現の粋を尽くした日本語エラーチェックサービス enno.jpを運営。 実は最近Go言語が好き。 仕事に関係ないすっとこブログ「あけてくれ」は2000年頃から多少の中断をはさんで継続、現在はnote.muに移転。

hachi8833の書いた記事

関連する記事

週刊Railsウォッチ

インフラ

BigBinary記事より

ActiveSupport探訪シリーズ