CSS設計とモジュール化の考え方にまつわるエトセトラ
前田 大地
こんにちは、セブンシックスのダイチです。今日は、HTML・CSSコーディングに関するちょっと専門的なお話をしたいと思います。
目次
CSSに正解はない、けれど・・・
HTML・CSSは、人によって書き方が違います。マークアップに使うタグや、id・classの名付け方、CSSの書き方など、10人いれば10通りのやり方が生まれます。たったひとつの「正しいやり方」が存在するわけではありません。不具合なく表示できていれば、10通りのやり方は、すべてが正解です。
とは言っても、やり方によってファイルサイズや可読性、メンテナンス性などは大きく変わります。サイトの規模が大きくなれば、チームでの作業となりますから、その差はさらに大きく開きます。そういった背景もあり、CSS設計の重要性は近年ますます高まってきました。
CSSの記述には、OOCSS、SMACSS、BEMなど様々な考え方があります。また、独自のルールを作っている制作会社も多いと思います。これらに共通するのは「モジュール化」という考え方です。ウェブページを構成するパーツを独立して設計することで、他の要素との干渉をなくし、メンテナンス性や再利用性を高めます。
セブンシックスは、大規模コーディング案件から、1ページのLPまで、多数のサイト制作に携わってきました。その中で感じたのは、企業ごとにガイドラインが異なっていても、サイトの規模が大きくても小さくても、考え方のベクトルは変わらないということです。つまり、基本的な考え方を身につければ、ほとんどの状況に対応できます。
今回は、ひとつの例として、セブンシックスが採用しているコーディングルールを紹介しながら、その考え方について解説していきたいと思います。
セブンシックスルールとその解説
モジュールのclass名はキャメルケースで。
キャメルケースは複数の単語をつなぎ合わせる際に、最初の文字を大文字にする記述方法です。class名は短ければ短いほど記述が楽ですが、それが何を意味するものなのかを直感的に理解できる必要があります。また、それぞれのモジュールに付けるclass名が重複しないようにしなければなりません。おのずと、1単語よりも2単語以上の組み合わせが中心になります。
「.postHeader」「.globalFooter」のように記述します。
モジュール内の子要素はスネークケースで。
モジュール内の親子関係を明確にする場合はスネークケースで記述します。BEMでは、子要素を表す場合には「__」を使いますが、アンダーバーを2つつなげるのは冗長です。これは、idやclass名に「_」や「-」が入ることを想定したものですが、キャメルケースを使用していれば考慮する必要はありません。
「.postHeader_ttl」「.postHeader_date」のように記述します。
上書きはチェインケースで。
例えば、「最新の記事だけ一部の表示を変えたい」ときのように、すでに定義されているclassの一部を上書きする際のイレギュラー対応にはチェインケースを使用します。こちらもBEMでは「–」を使いますが、モジュール名をキャメルケースで統一していれば「-」でOKです。
「.postHeader-latest」のように記述します。
セレクタの階層を深くしない。
セレクタの階層を深くすると、優先度がややこしくなります。先述の命名規則であれば、自然と深い階層が避けられます。
/* 例1 ダラダラ: */ .postHeader .postHeader_ttl { margin: 0; }
と、ダラダラ書く必要はありません。「.postHeader_ttl」と「.postHeader」が親子依存にあるのは、名前からも一目瞭然ですから、
/* 例1 スッキリ: */ .postHeader_ttl { margin: 0; }
と、シンプルにこれで良いのです。先頭にモジュール名が付いていれば、他のclass名とかぶることもありません。
次に、HTMLを見ていきましょう。
<!-- 例2 ダラダラ: --> <div class="postHeader"> <h1 class="postHeader_ttl">タイトル</h1> <div class="postHeader_cont"> <p class="postHeader_cont_cat">カテゴリ名</p> <p class="postHeader_cont_date"><time class="postHeader_cont_date_time">日付</time></p> </div> </div>
いくつかのCSS設計ルールでは、セレクタの優先度やメンテナンス性を意識するあまり、すべてのタグにclass名を付けなくてはならないというおかしな状況が発生します。依存関係もアンダーバーが付いてどんどん深くなっていきます。これは、現実的ではありません。
<!-- 例2 スッキリ: --> <div class="postHeader"> <h1 class="postHeader_ttl">タイトル</h1> <div class="postHeader_cont"> <p class="postHeader_cat">カテゴリ名</p> <p class="postHeader_date"><time>日付</time></p> </div> </div>
上記のように、すっきりと記述することができます。モジュール内の構造がシンプルであれば、アンダーバーを複数つなげて完璧な親子関係を表さなくても、どのモジュール内の子要素なのかが理解できれば十分なケースは多いです。また、内包する子要素があらかじめ決まっている箇所であれば、class名を省略してもCSSの記述に問題ないケースもあります(上記だとtimeの箇所)。時と場合によりますが、必ずしもバカ正直にやる必要はないということです。
モジュール単位でCSSをまとめる。
CSSは、上から順に読まれ、下にある記述で上書きされていきます。ただし、セレクタには優先度が決まっており、優先度が高い記述を、それより優先度が低い記述で上書きすることはできません。モジュール単位でまとめてCSSを記述しておけば、後から見ても理解しやすく、セレクタの優先度も把握しやすいため、意図しない上書きや打ち消しを防ぐことができます。
広く浅いものから順番に。
美術の授業で、薄い色から塗っていくよう教わった記憶があります。CSSも同じです。薄く広く適用するCSSから始まり、ピンポイントで適用させるCSSに向かっていきます。まずは全体のベースとなるCSS、例えばnormalize.cssなど。次に、タグごとのスタイル。そして、共通モジュール。最後に、個々のページの固有のスタイルと続きます。徐々に濃い色を上から塗り重ねていくイメージですね。
おかしな汎用classに頼らない。
ずっと昔、CSSのモジュール化が氾濫した時期に、「.mt10(margin-top:10px !important;)」とか「.mb20(margin-bottom:20px !important;)」などの汎用的なclassを使用するサイトが出現しました。これは一見、便利なように思いますが、HTMLタグにインラインでCSSを記述するのを回りくどくやっているのと同じです。このような汎用classはコーダーさんの思考を停止するので、できるだけ避けたほうがよいでしょう。
中身が変わっても、崩れないように。
モジュールは、使いまわされるものです。最初は、1箇所でしか使われていなくても、将来的に使用箇所が増えることも予想されます。そのとき、今あるデザインカンプとまったく同じ量のテキストが入るとは限りません。1行だったものが2行になったり、逆に短くなることもあります。デバイスによって折り返し位置が変わるかもしれません。あらかじめ中身が変動しても崩れないよう配慮してcssを記述しておくことが大切です。
CSSは難しくない、だから難しい。
HTML・CSSコーディングは、JSなどのプログラミング言語に比べてシンプルで理解しやすく、誰でもはじめることができます。シンプルだから、考え方や経験などで差が出やすいものでもあります。この記事が、ただ正しく表示するためだけではなく、もう一歩進んだコーディングを目指すキッカケになってくれたら嬉しいです。