本記事は2015年1月に開催されたHTML5 Conferenceでお話させていただいた、 「Beyond CSS Architecture」というCSS設計のセッションをフォローアップする記事です。
本記事では、このセッションの概要と補足、またセッション中に説明できなかった点などについて書いていきます。
※当日のセッションの動画・スライドも公開されているので、文末からご覧ください。
CSSの難しさと、昨今のCSS設計事情
この近年、CSSにおける設計論というのが話題に出てくるようになりました。筆者も拙著『Web制作者のためのCSS設計の教科書』を書いたり、各地でCSS設計をテーマとした講演をする機会が多くありました。
CSSの難しさというのは、石本氏によるCSSコードの評価についての記事にも書かれているのですが、CSSは良くも悪くも厳格なコード規約は少なく、ただ宣言的に書けばいいだけです。セレクタとその詳細度や、後出しされたルールの方が優先されるという、シンプルがゆえに「書く」のは簡単ですが、「直す」のは容易ではありません。
Normalize.cssの作者であり、現在Twitterのエンジニアであるニコラス・ギャラガー氏(@necolas)のツイートを引用するならば、次のように考えられるかどうかです。
Replace "can you build this?" with "can you maintain this without losing your minds?"
— Nicolas Gallagher (@necolas)
複数人のチームでの開発はもちろんですが、自分のひとりの開発であったとしても、いざメンテナンスするとなったときに、数日前に自分が書いたCSSを呪うようなことはよくあります。
中長期的に運用されるWebサイト、Webサービスにおいては、その運用に耐えうるメンテナブルかつ、拡張性のあるCSSを書くことは非常に重要です。 こうしたCSS設計の話題が以前よりも見かけるようになったのは、単純な数ページのWebサイトよりも、少しリッチで複数のテンプレートが必要なWebサイト、Webサービスが増えてきていることもあり、メンテナブルなCSSにするための設計とは何か、というのが求められているからかもしれません。
OOCSSとBEM
セッション内でも取り上げているOOCSSとBEMは、CSS設計を考える上で避けられない方法論のひとつです。
OOCSSは、ページ上で繰り返されるビジュアルパターンをオブジェクトと考え、そのオブジェクトはHTML/CSSまたはJavaScriptのコードの固まりで構成されます。それはボタンやリスト、見出しというような単位であったり、場合によってはただ文字色を赤くするためのものかもしれません。こうした作られた小さなオブジェクトをレゴのように組み合わせてUIを作るというのが、OOCSSの基本的なアプローチです。
BEMは、Yandexという会社のフロントエンド開発チームによって考えられた開発手法です。BEMはUIをBlock,Element,Modifierという分類で設計するのですが、BEMで使われている命名規則とその記法が特徴的で、Blockを名前空間として使うのが良いアイデアとされています。
1 2 3 4 5 6 |
.menu { ... } /* Block */ .menu__item { ... } /* Block + Element */ .user { ... } /* Block */ .user_login { ... } /* Block + Modifier */ .user__avatar { ... } /* Block + Element */ .user__name { ... } /* Block + Element */ |
このコード例では.menu
がBlockの単位となり、またそれがセレクタの接頭辞にすることで、マークアップ上でつけられたクラス名を見るだけで、どのUI(Block)に依存するものかが分かります。例えばclass="item"
だと抽象的すぎて何に依存しているかわかりませんが、.menu__item
であれば分かる、ということです。
また_
、__
の記号の組み合わせは、設計上のルールとして、単語間がどういう関係性を持つのかを明確にしています。__
は一見冗長で、普通に名前をつけるときには使わなそうですが、それが良い意味でただの命名ではなく、デリミタ(区切り)として使われているということです。
このBEMのアプローチの細かなルールは必ずしもオリジナルのBEMに倣っているものばかりではなく、MindBEMdingのような独自のルールで運用されることもあります。筆者のFLOCSSも、いろいろなものを参考にして作成したものです。
モダンなCSS設計の誤解
OOCSS、BEMについて言及される記事を見ると、これらやCSS設計における大きな誤解を招いていると感じることがあります。
OOCSS派か、BEM派か、というような表現も見かけますが、多くの場合、OOCSSは複数のクラスを組み合わせるアプローチ、BEMは単一クラスのアプローチ、というような解釈をされているようです。
OOCSSが体系化された当時にはSassのようなメタ言語もなく、OOCSSを実現するためには複数のクラスを組み合わせるアプローチが適切だったというだけでしょう。事実、彼女自身が“OOCSS and Preprocessors in a tree, K-I-S-S-I-N-G”という講演で、OOCSSとSassを組み合わせたアプローチについて述べています。
また提唱者であるニコール・サリバン氏が関わったプロジェクトにおいては、font-size
という単位でもオブジェクトとして分解することが、数百と宣言されるfont-size
プロパティを、たった数個のクラスで管理することに意味がありました。
ただそのいくつかの例が拡大解釈され、.red {color: red;}
や.large {font-size: 36px}
というような、見た目だけの、コンテンツ派生の意味をもたないクラスを複数組み合わせるアプローチがOOCSSである、と考えられることは少なくありません。
しかし、OOCSSの本質は、現在のHTML/CSSでは難しいモジュラーなアプローチを実践するためのパラダイムである、と筆者は考えています。
一方、BEMについてもいくつかの誤解があるように感じています。Block、ElementあるいはModifierとしての命名と設計は、マークアップを見て、その構造をセレクタにするものではありません。
1 2 3 4 5 6 7 8 |
<nav class="globalNav"> <ul> <li> <a href="/home">Home</a> </li> <!-- more --> </ul> </nav> |
例えばこのようなマークアップがあった時に、その構造を意識してしまい、次のようなCSSにしてしまうことがあります。
1 2 3 4 5 6 7 8 |
<nav class="globalNav"> <ul class="globalNav__menu"> <li class="globalNav__menu__item"> <a href="/home">Home</a> </li> <!-- more --> </ul> </nav> |
極端な例ではありますが、近いコードを見ることはあるのではないでしょうか。こうなってしまうと、BEMが冗長すぎる、気持ちが悪い、というのは素直な感情だともいえます。
しかし本来のBEMらしい考え方であれば、このようなマークアップを元にセレクタに命名するものではなく、UIをBlock,Element,Modifierのツリー構造で考え、それが名前にも与えられるものです。
この例でいえば、globalNav
をBlockとするならば、それを構成する要素は次のようになるかもしれません。
1 2 3 4 5 6 7 8 |
<nav class="globalNav"> <ul class="globalNav__menu"> <li class="globalNav__menuItem"> <a href="/home">Home</a> </li> <!-- more --> </ul> </nav> |
そもそも、もっと小さな単位にするべきかもしれません。
1 2 3 4 5 6 7 8 |
<nav class="globalNav"> <ul class="globalNav__menu menu"> <li class="menu__item"> <a href="/home" class="menu__target">Home</a> </li> <!-- more --> </ul> </nav> |
どちらが正しいかというものではなく、その時々で適切な命名や分割があるはずですが、少なくともマークアップの構造をなぞって親子関係を命名で表すのが、BEMの命名規則というわけではありません。
最後の例を見ての通り、BEMの記法であっても、複数のBlockとElement、つまりはそれぞれはOOCSS的にいえばオブジェクトであり、組み合わせによって作られるわけです。
つまり、OOCSS派かBEM派かという天秤があるわけではありませんし、思想として良いところを取り入れて、プロジェクトに適切な方法論、設計を考えることが重要です。
逆にいえば、これらは銀の弾丸というわけでもありませんから、OOCSSやBEMがすべての問題を解決するわけでもありません。プロジェクトの規模やその運用の方向性によっては、もっと単純な規約のもとでCSSが書かれていても構いません。
いずれの場合も、そのプロジェクト内において一貫性が保たれていることのほうが大事で、Ideomatic CSSから引用するならば、次のようなことです。
どんなに多くの人が貢献したとしても、どのコードも一人で書いたようにすること。
— Ideomatic CSS
セッションで紹介しているツール、スタイルガイドやStyleStatsのようなツールは、一貫性を保ったCSSを書くための補助となるものです。
これらもまたツールでしかなく、導入しただけで問題が解決するというわけではないので、どのように運用するか、自動化などを含めた仕組みを考えることがより重要です。
まとめ
セッションの最後にWeb Componentsに触れていました。Shadow DOMによって、今のHTML/CSSにないスコープの概念がもたらされれば、現状HTML/CSSをモジュラーに設計・実装するためのいくつかの課題は解決するかもしれません。
しかし、それによってCSS設計が簡単になるか、といえば決してそうではありませんし、どちらかといえばより難しくなるかもしれません。
またWeb Componentsの実用は少し先かもしれませんが、現在でもReactのようなものを採用したプロジェクトにおいては、CSSはどのように設計するか、というのは課題として出てきています。個人的にはそれを考えることは、HTML/CSSをより面白くするものでもあります。(その分の苦しみも多くありますが)
どのような未来がくるにせよ、よりよいCSS設計をするためには、より多くのパターンを知ることだと考えています。
同じリスト型のUIを組むにしても、どのようなパターンが目の前のプロジェクトにおいて適切か、それはパターンを多く知らなければいけません。
そのためには、世の中に多く公開されているフレームワーク、またはプロダクトとして公開されているWebサイトやWebサービスのコードを読むことが大事です。続々と出てくる、新たなOOCSSやBEMのような方法論たちも、食わず嫌いはせず一読してみてください。
CSS設計は非常に難しく、壊れないCSSを書くというのは不可能です。私は次の言葉を胸に、いつもCSSを書いています。
壊れない完璧な設計を求めるのではなく、壊れたときに勇気を持って修復できる設計を
— 斉藤 祐也
はじめから作ることはもちろん、どれだけシミュレーションや設計をしても壊れるときはありますから、それをいかに直しやすいものにするか、そしてそれが他の開発者にとって可能であり、数日後の自分でも直せるようなCSSを書くようにしましょう。
当日のセッションの動画・スライドは、こちらからご覧ください。