技術的な話、テクニカルなテーマを取り上げているようで最近はご無沙汰気味な気がする、こちらのオウンドメディアですが、たまには技術的な話もしてみましょう。
今回のテーマは、それだけで多数の本が生まれそうな気がする「CSS設計」で。
厳密にいうとCSS設計のお話というよりは、今現在取り入れて、安定しつつあるデザインシステム、ボイラープレートのお話が中心になるのですが、一旦「CSS設計」と括らせてください。
色んな技術体系があり、先人達が永年の議論を経て築き上げてきた多様な思想に触れながら、「結局、これが使いやすい」と結論が出つつある筆者なりの最近の考え方へ向けて、少しずつ深みへハマっていきましょう。
目次
コンセプトはパフォーマンスと組みやすさの両立
長々と語る前に、結論から提示してしまいましょう。
まだまだ整理途上ですが、現在の思想を反映しているのが、こちらのリポジトリです。
https://github.com/Yuuji-Hasegawa/skeleton-kit
『EVERY LAYOUT』をベースに取り込んだSass(Scss)に、BEMベースの考え方やFLOCSS、近年の流行りというか主流といっても良さそうなTailwind的なユーティリティファーストな思想も一つにまとめた結果の産物です。
Tailwindほど顕著ではありませんが、複数のクラスを付与しまくるマルチクラスのスタイリング、マークアップがベースで、「ぶら下げるものが多すぎる」とか「擬似要素、擬似クラスを使いたい」という時はコンポーネントとして実装するようなイメージです。
基本的に、セレクタに対してのスタイリングはリセットCSSとその余波を調整する部分に留め、それ以外は基本的にクラスに対するスタイリングとし、IDはJSでの制御やページ内のアンカーリンクのみに使うという考え方も徹底しています。
なお、リセットの際は強めのリセットCSSを採用し、スタイリングとセレクタ、構造との分離も同時に行っています。その上で、できるだけ短く、さらに分かりやすい命名規則とするために、セレクタを上書き、オーバーライドするようなネーミングも採用しています。
例えば、今までは`.c-heading`や`.c-display-l`とc-(コンポーネントの接頭語)+何かしらの意味があるネーミングとしていましたが、最近はこれを`.c-h1`と`.c-h1-ext`のように「h1に相当するスタイリング」と「extra = それの派生系」という形を取っています。
こうすることで、「h1」がどんなスタイルなのか、どのクラスを割り当てるのが適切かを悩むことがなくなりますし、セレクタがどんなものであっても、「どれに相当する要素なのか」も掴みやすくなります。それより大きいのか、小さいのかという判断も付けやすくなります。
カスタムプロパティもグローバルとローカルを使い分けたり、二段重ねで影響箇所、挿入される箇所を限定することで使い勝手の向上を図ったり、余白の違いや背景色の違いから来るmodifierの命名で余計に悩まなくても済む実装環境の構築、実現にも繋がっていたり、初手の使いやすさも再利用のしやすさも格段に向上しているという、実感があります。
BEMやFLOCSS、Atomic Designに基づくCSS設計は確かに破綻しにくく堅牢ですが、どこまでをブロックと考え、どこからをエレメントやModifierと考えるのかが難しかったり、意味のある名前を考えてしまうと、再利用性の問題が出てきたり、シングルクラスしか許さないような組み方も併用してしまうと、余白や色が若干異なるだけ、アウトラインや下線があるかないかだけでmodifierが増えるような場面もあり、長く使い続けるにはハードルが高く、またプロジェクトを跨いだ流用、再利用も難しいという経験則があります。
その一方で、Twitter BootstrapやTailwind CSSといった誰かが用意した既存のフレームワークの場合、慣れるまでに時間がかかりますし、「使わないものは取り除ける」と言われても、開発環境の都合上「やっぱり要らないよね」という気持ちになります。余白や文字サイズのレベル分けやバランスにしても、調整可能ですが、「自分の好み」や「その案件に必要な調整」に至るまでに、いくらか手間がかかるのも取り回しの悪さ、とっかかりにくさに繋がります。
ヘルパークラスの利点、ユーティリティファーストによるコード削減の恩恵もある程度受けながら、コードゴルフに陥らない程度の適当さ加減でも、そこまで大きな問題を引き起こさないという点で、今回辿り着いている形をしばらく使い続けるのではないか、というのが現段階の回答です。
パフォーマンス改善を考えるなら、クラスベースのスタイリングが基本
Webサイトの表示速度、パフォーマンスの改善が気になるという方は、2017年や2018年頃と少し古い書籍になりますが、『Webサイトパフォーマンス実践入門 高速なWebページを作りたいあなたに』(Jeremy L. Wagner 著 翔泳社 https://www.shoeisha.co.jp/book/detail/9784798155098)か、『Webフロントエンド ハイパフォーマンス チューニング』(久保田 光則 著 技術評論社 https://amzn.asia/d/clmjEWV)をまずは紐解きましょう。
すでに考え方が古くなっている解決策も掲載されていますが、何がどうなるとパフォーマンスが向上して、逆に悪化するのかということも、基本的なことが掲載されているので、現在でも学べる箇所は多いでしょう。
これらの書籍やCSS設計の思想から分かるのは、「セレクタに対するスタイリングは基本的にNG」ということ。これはなぜかというと「セレクタやHTMLの組み方を変えると見た目が維持できない」のはメンテナンス性や内部SEOの観点から問題があり、「詳細度を追いかけながらCSSを解釈し、レンダリングしなければならない」というレンダリングコストの観点から問題があるから、です。
例えば、`div > ul > li > a {text-decoration: underline;}`と実装していた場合、ブラウザはaに対するスタイリングを計算し、liの中にあるaに対するスタイリングを計算し、ul以下のliの中のaのスタイリングを計算し、divの中のulの中の…..と、基本的には右にあるものから解釈し、レンダリングを行います。
また、この例ではリストをulとして実装していますが、途中でolに変更したくなったり、そもそも表組や定義づけをしたdlを使いたくなった場合はどうします? リストの外側もdivじゃなくて、pやsection、headerやfooterに変更したくなる可能性もあり得ます。
あるいは、HTMLを実装する側がCSSの実装状況を知らず、たまたま例のスタイリングが適用される形で組み上げてしまい、「想定外のスタイリング」が実現してしまう場合もあるでしょう。これでは再利用性やメンテナンス性の観点で、問題がないとは言えません。
更に、「IDを使えば優先的に解釈されるからいいじゃん」とID、つまり`#hoge {}`での実装を増やすのも、あまり良い方法とは言えません。「優先的に解釈して欲しい」から一意のIDを割り振るのに、そのIDを沢山割り当てすぎると、どうなるでしょう?
ブラウザは人とは異なるので、大勢から「優先して」と言われても捌き切れるとは思いますが、やらない方が良い、控えめにした方がいいというのはよく分かるでしょう。
つまり、これまでの話をまとめるとスタイリングは基本的に、クラスベースで行うこと。ID指定はページ内のアンカーリンクや、ユーザー補助、アクセシビリティで用いるWAI-ARIAを補強するため、JSで操作する対象を明確にするために留め、IDによるスタイリングは行わないのが良いでしょう。
クラスベースでも、詳細に追いかけなければならない組み方、例えば`.hoge .fuga{}`と言った組み方をしてしまうと恩恵は受けにくいので、`.hoge {} .fuga{}`と分離するか、`.hoge__fuga {}`のようにBEM的な発想で親子関係やModifierとして実装しよう。
BEMやシングルクラスで悩むより、マルチクラスがベター
堅牢さや後々のメンテナンス性を鑑みると、BEM的な発想で一つのクラスしか割り当てない実装が理想的であるとは思いますが、実際の導入や実装の手間を鑑みると、ユーティリティファーストな複数クラスを割り当てる実装方法、マルチクラスを用いた手法が便利です。
BEMやシングルクラスは微妙な違いでModiferが増えてしまったり、意味がありすぎるネーミングにしてしまうと、後から再利用性で困ることがよくあります。
例えば、header-linkとしてヘッダーのリンク要素をスタイリングしたり、cta-btnやcta-boxといったネーミングでCTA要素をスタイリングした後、フッターでもheader-linkと同じ見せ方を使いたい場合や、お問い合わせのsubmitボタンでcta-btnと同じ見せ方にしたい場合、「あの名前はまずかったな」と思うか、「今はこれでいい」と暫定措置でそのままにしたつもりが、いつまでもそれが残ってしまうというのも、よくある話でしょう。
また、特定コンポーネントの周囲や余白、背景色やテキストカラーをできるだけ持たせないようにする「UIコンポーネントにmarginをつけるな」ともよく言われますが、そうは言われてもmarginの違いやpaddingの違いをModifierとして、実装したくなるでしょう。その時に、「意味のある名前」を考えすぎてしまい、無限にModiferが増えるか、後から合わなくなるクラス名になってしまうか、名前を考えるために実装に割く時間を費やしてしまうの、いずれかの沼にハマる可能性も高いでしょう。
そこを、ヘルパーとしてユーティリティクラスを用意した上で、複数のクラスを付与するマルチクラスを許容するようにすると、marginの違いやpaddingの基本的な設定、文字や背景色関連はユーティリティに任せ、必要な部分だけをコンポーネントとして実装すれば良い形に切り分けられます。
また、あくまでも主観ですが、意味のある名前を考えるために費やされる時間も減り、「どう実装しようか」と悩む時間、「やる気を出して頑張らなきゃ」と身構える時間、精神的な負担も削減しやすくなる印象です。
その一方で、ユーティリティファーストだからといって、クラスを目一杯付与して、全てをそれで実装するというのも、あまり現実的ではないという経験則もあります。
ヘルパーとして用意しておいてもあまり使う事がないスタイリングや、それらを沢山盛り込むコンポーネントの場合、marginやpadding、フォントサイズぐらいはユーティリティでも良いけれども、そこから先は個別のコンポーネントとして実装してしまった方が、構築もしやすいし、後々の管理も比較的しやすいというのは、これまでの経験から来る回答です。
ユーティリティファースト、Tailwindの考え方やStyleXのやり方が至上であり、それが最善であるとは言い切れないし、BootstrapはBootstrapでデファクトスタンダードっぽいけれども、使いにくいところ、要らない要素も含まれる印象ですし、BEMやシングルクラスによる実装、FLOCSSだけを信奉するのも、バランスがよくない上に、利便性も再利用性も高くないなというのが、これまでの学びや経験則から来る考え方です。
CSS設計、実装も「守破離」でいい
今まさにHTMLの実装やCSS設計を学んでいる最中の方、どこかの組織やプロジェクトの中で、既存のコーディング規約やデザインシステムを踏襲しなければならない方は、まずは目の前に用意されたもの、またはすでに確立されているものをとことん学ぶべきだと思いますが、その段階を過ぎたのなら、CSS設計や実装も「守破離」というか、違う思想に浮気して、使う側にとって都合が良いところをチェリーピッキングし、新たな形を模索してしまっても、そんなに悪いことだとは思いません。
「よその思想、流派にも染まろうとするとは邪道だ」と破門される師弟関係であれば、今の思想、流派からはみ出ない方が良いですが、巷のWeb制作者は流浪の流れ者も多いと思うので、「これが良さそう」だと思ったら、どんどん食いついて、自分に合うか合わないか、長く採用すべきかどうか、一回サンドボックス的に遊んでみるレベルにとどめた方が良いかは、個人の好き好きで良いでしょう。
「適当にやったら破綻するから、設計や思想があるんだ」というご意見もよく分かるというか、極めて真っ当なご指摘ですが、それ故に実装しにくくなる、手を動かしにくくなる心理的な障害になるのであれば、「こうやったら破綻する」をある程度理解した人が、経験則を活かして多少自由にやる、その人なりの流儀を作り上げるのは、そんなに悪い手法ではないでしょう。
我流で好き放題やる前に、パフォーマンス最適化の考え方を学び、様々なCSS設計やその背景を学習した上で実情も経験し、その上で「破」と「離」の段階に到達する。「守」をとことんやった後の「型破り」なら、あとは全てを自己責任で解決もできるでしょうし、周りや環境が許すなら、自由にやれば良いと思います。
学びが不十分なままの好き勝手はただの無秩序、「形無し」になってしまうので、「守」の段階が不十分だと思うなら、無理せず既存のCSS設計やルールを守るようにしましょうね。
表示も実装もハイパフォーマンスで
BBNでは表示速度のパフォーマンスはもちろん、実装の速さという観点でのパフォーマンスも最大化できる方法を模索しています。表示速度を損なわないクラスベースのスタイリングや、余計な実装を回避しやすいユーティリティファーストなマルチクラスのアプローチを採用しつつ、独自のCSS設計やデザインシステムの構築にも取り組んでいます。
プロジェクトを跨いで再利用しやすいもの、生産性を向上させられるものを求めて、公開可能なものは積極的にGithub上でもオープンにしていますので、git cloneなどの操作が苦でない方は、気軽に使ってみてください。また、「こうした方がもっと良いのでは?」というご意見があれば、プルリクエストやご指摘も大歓迎です。
生産性が高く、汎用性も高いデザインシステムを構築し、作業の標準化も見据えて取り組めればと考えておりますので、もしよろしければお力添えいただけますと幸いです。
また、そんなBBNと共に、Webサイト制作の環境整備やWebマーケティングに取り組んでみたいという方がいらっしゃいましたら、お気軽にご連絡ください。ご質問やご相談も、いつでもお待ちしています。