CSS設計、やってますか?
何も考えずに命名したりCSSを書いていると、拡張性や管理性を損なうとんでもないものが出来上がります。
作ったときはいいけど、後で修正したり追加したりするときに、どこか知らんとこがついでに崩れたり、反映されないからどんどん!importantで上書きしてガチガチに絡まったCSSになったりします。
そういった問題を防ぐためにも、CSS設計をちょっとでもいいので心がけるようにしていきましょう。
最初はちょっとしんどいかもしれませんが、慣れてくると「どんな名前をつければいいか」に悩む時間も減りますので、効率爆上がりです。
僕は、BEMとSMACSSという2つの設計方法をなんとなく取り入れ、CSS設計を行っています。
両方とも完璧に取り入れようとすると逆にしんどいので、なんとなくでいいんです。
とりあえず意識してみることから始めて、もっとこうしたほうがいいかなーと思ったら改善していくといった流れでいくのがオススメ。
CSS設計ができるようになると、
- コーディングが早くなる。
- わかりやすいコードを書ける。
- メンテナンス性がいいので、修正や追加のときも楽ちん。
- 一歩上に行ける気がする
いいことづくしです。
まずはBEMとSMACSSがどんなものなのかをだいたい説明して、組み合わせることのメリットを紹介したいと思います。
ちなみに、僕のフレームワークをGithubで公開していますので、SMACSSについては合わせて読むとわかりやすいと思います。
それでは、参りましょう。
目次
BEMとは?
下の記事でもさらっと紹介していますが、
Block、Element、Modifireという3つの概念の頭文字をとったものです。
難しいことは考えず、基本的にこの3つを使ってclass名をつけるということだけ頭に入れておきましょう。
Block
ヘッダー、フッターや記事一覧の繰り返し要素など、大まかなパーツ。
Blockの中にBlockを含んでもいいが、cssではBlockを入れ子にしない。
Element
Blockに所属する、細かいパーツ。
その所属するBlock内でのみcssが機能する。
Modifire
Block、およびElementにて、既存のものとほとんど一緒だけど、ちょっとだけ違う部分があるというときに使う。
バリエーションを与える役割がある。
命名方法
命名方法は人によってけっこう違うみたいだけど、Block、Element、Modifireの関係性がわかればOK。
例えば僕は以下のように命名します
{Block}-{Modifire}
{Block}__{Element}-{Modifire}
BEMを使って命名する場合、最初は必ずBlockからはじまり、ElementとModifireの前にそれぞれ別のつなぎをくっつけます。
アンダースコアとか、アイフンとか、なんでもいいです。
ただ、Elementの前はアンダースコア2つというのはけっこう共通認識みたいなので、これはこれでいったほうが他の人が見たときに、「あ、BEMだな」とわかりやすいかと思います。
例
図で説明するとこんな感じ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
<div class="archiveItem"> <a class="archiveItem__inner"> <div class="archiveItem__thumb"><img src="" alt=""></div> <div class="archiveItem__right"> <h2 class="ardhiveItem__title">タイトルタイトル</h2> <p class="archiveItem__text">テキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキスト</p> </div> </a> </div> <div class="archiveItem"> <a class="archiveItem__inner"> <div class="archiveItem__thumb"><img src="" alt=""></div> <div class="archiveItem__right"> <h2 class="ardhiveItem__title">タイトルタイトル</h2> <p class="archiveItem__text">テキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキスト</p> </div> </a> </div> <div class="archiveItem"> <a class="archiveItem__inner"> <div class="archiveItem__thumb"><img src="" alt=""></div> <div class="archiveItem__right"> <h2 class="ardhiveItem__title">タイトルタイトル</h2> <p class="archiveItem__text">テキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキスト</p> </div> </a> </div> |
ちなみBlockは、キャメルになってもいいです。
こんな感じで各パーツ全てにclass名をつけます。
そして驚くべきことに、これら全てのパーツはcssで入れ子にならないということに気づくかと思います。
入れ子にならないというのはかなり安全で、読みやすく、そして指定しやすいです。
さらに、命名にかかる時間も大幅に短縮されます。Block名さえ考えれば、Elementはtextとかthumbとか適当でいいですからね。
これが、入れ子だとどうでしょうか。
下のように、全然スタイルが違う.archiveListと.rankingListがあるとして、
1 2 3 4 5 6 7 8 9 |
<div class="archiveList"> <h2 class="title"></h2> <p class="text"></p> </div> <div class="rankingList"> <h2 class="title"></h2> <p class="text"></p> </div> |
中に.titleと.textがある。cssは、こんな感じですよね
1 2 3 4 5 6 |
.archive .text { } .ranking .text { } |
じゃあ、もし次のような構造だったら?
1 2 3 4 5 6 7 8 9 10 |
<div class="archiveList"> <h2 class="title"></h2> <p class="text"></p> <div class="rankingList"> <h2 class="title"></h2> <p class="text"></p> </div> </div> |
一気にややこしくなりましたね。
こうなってくると、うーんどう名前つけようか…となってくるわけですが、BEMだと一瞬です。
「いやこんなんcss書くのめんどいやん!」と思うかもしれません。
しかし安心してください。
ここでSassの出番です。
cssでは以下のように書くところを、
1 2 3 4 5 6 7 8 9 10 |
.archiveItem { margin-bottom: 20px; } .archiveItem__inner { display: flex; padding: 10px; } .archiveItem__thumb { margin-right: 20px; } |
Sass(scss)では以下のように書けます。
1 2 3 4 5 6 7 8 9 10 |
.archiveItem { margin-bottom: 20px; &__inner { display: flex; padding: 10px; } &__thumb { margin-right: 20px; } } |
猛烈にわかりやすいですよね。
実際は入れ子構造になってないのに、Sassなら入れ子で書けるし、親子関係が一発でわかる。これがBEMのメリットです。
いやModifireは?
忘れかけてましたが、Modifireの使い方もやっておきましょう。
Modifireは、ほとんど同じだけど、ちょっとだけ違う、言うなれば「別パターン」を作りたいときに使用します。
例えば以下のように。
左右の順番が違うだけで、あとは全部一緒。ってときにほんの少しスタイル書き足すだけなのに(ちなみに順番を逆にするのは ”flex-direction: row-reverce;” でいけます)、それぞれ別々のBlockとして命名するのはめちゃくちゃめんどくさいですよね。
そこで登場するのが、Modifireです。こんな感じで命名します
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<div class="archiveItem"> <a class="archiveItem__inner"> <div class="archiveItem__thumb"><img src="" alt=""></div> <div class="archiveItem__right"> <h2 class="ardhiveItem__title">タイトルタイトル</h2> <p class="archiveItem__text">テキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキスト</p> </div> </a> </div> <div class="archiveItem archiveItem-reverce"> <a class="archiveItem__inner"> <div class="archiveItem__thumb"><img src="" alt=""></div> <div class="archiveItem__right"> <h2 class="ardhiveItem__title">タイトルタイトル</h2> <p class="archiveItem__text">テキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキスト</p> </div> </a> </div> |
もともとのBlockのClass名はそのまま残したうえで、”-{Modifire}”をくっつけたClassを更に追加します。これにより、ほとんどhtmlを書き換えることなく、さらにぱっと見ただけでも「あ、基本同じだけど別パターンあるな」ということがわかりやすいです。
これでModifireも大丈夫ですね。
じゃあ次は、SMACSSの話をしましょう。
SMACSSとは?
SMACSS(スマックスと読むらしいです)とは、BEMとはまた違ったCSS設計の一つです。
本当はけっこう奥が深いんですが、今回のテーマは「BEMとSMACSSをなんとなく組み合わせたいい感じのCSS設計」なので、ひとまず全体をふわっと説明したあと、必要な部分だけ掘り下げていきましょう。
CSSのカテゴライズ
SMACSSの基本の考え方は、CSSを5つのカテゴリーに分類することです。
- ベース
- レイアウト
- モジュール
- 状態(ステート)
- テーマ
ちなみに、僕はテーマは使ってません。
ベース
要素そのものにつけるスタイル。
p, div, input等、classに関係なく基本的なスタイリングを行う。リセットCSSもここに属すると考えていい。
ここでは、IDやclassによる指定は行わないが、属性([type=”text”])や疑似クラス(:hover)は使ってもいい。
レイアウト
迷ったら全部ここ。
モジュール
再利用可能なもの。
ボタンとか、汎用クラス(.mb20みたいなやつ)もここに属する。
「いろんな場所、ページで共通して使われるパーツ」を書くといい。
“modBtn”,”modTitle”のように、”mod”をつけることが多い。
モジュールでは、BEMによる命名規則を行わない。
状態(ステート)
あるclassに対し、状態が変わる際に付与されるclass。
たとえば、「メニューが開いたとき」なんかに使う。”is-open”,”is-active”のような命名のしかたをする。
この命名をすることで、JavaScriptの指定がすごくやりやすい。
例えば.menuに対し、開いたときの状態をスタイリングしたい場合、
1 |
<div class="menu is-open">メニュー</div> |
のように書く。
テーマ
色や背景等、サイトの全体で統一されるスタイルを書く。
BEMのModifierがあるし、Sassだと変数が使えるので正直いらないと思う。
厳密にはけっこう違う(特にレイアウトとか)けど、僕がやってるやり方の場合、これでいいんです。なんとなくで。次いきましょう。
SMACSSの真骨頂はSassで発揮される
今まで紹介した、cssのカテゴリ分けですが、これだけだと「で?分けてどうすんの?」って感じですが、これはSassを使うことで便利になります。
Sassには、cssにコンパイルするときに複数のsass(scss)ファイルをまとめるという機能があります。
これを応用し、以下のようにファイルを分けます。
“_base”,”_layout”,”_modlue”,”_state”には、それぞれカテゴリ分けされたcssを書きます。
style.scssは、これらをまとめる記述だけです。
1 2 3 4 5 6 7 8 9 |
@charset "UTF-8"; // Include Base Style @import "base"; // Styling Start @import "layout"; @import "module"; @import "state"; |
ファイルの前にアンダースコアがあるものは、コンパイルの際にcssファイルとして生成されないという特徴を利用しています。
逆にこれをつけないと、最終的にほしいのはstyle.cssだけなのに、他のいらないファイルも全部生成されて邪魔になっちゃいます。
僕の場合は、更にアレンジを加えて、baseからリセット(もしくはノーマライズ)CSSだけを切り離した”normalize”ディレクトリ、ページごとにスタイリングするための”page”ディレクトリ、mixinや基本設定を記述する”lib”、外部ライブラリのスタイルを上書きするための”vend”といったファイルを作っています。
今回は触れませんが、興味があれば記事の冒頭で紹介したGithubを眺めてみてくださいね。
いちおうthemeも入れてるんですが、ほぼ使うことはありません。
SMACSSは、カテゴリ分けすることにより可読性、メンテナンス性、拡張性の向上といったメリットがあります。逆にこれをSassを使わずcssだけでやろうとすると面倒なので、使うときはSassとセットだと認識していたほうがいいと思います。
なんでBEMとSMACSSを組み合わせたの?
組み合わせるといっても、ただ単に
- BEMで命名して
- SMACSSっぽくカテゴライズする
だけなんですが、SMACSSはその概念の一部のみを利用しています。
その理由は、SMACSSのデメリットを解消するためです。
SMACSSは非常に便利なんですが、とにかく難しくて考えることが多く、下手をすれば逆に時間がかかります。
いくら後々メンテナンス性がよくなるといっても、作るときに疲れるのはいやです。
特に、レイアウトとモジュールの使い分けの部分ですね。
この2つ、実際はもっとややこしいんです。
たぶん、この記事に書いてあるレイアウトとモジュールの概念は、実際にSMACSSでググると出てくるものと全然違うだいぶゆるいものになっていると思います。
なんでこんなにゆるくなったかというと、このめんどい部分をBEMの命名規則に肩代わりさせてるからなんですね。
BEMを使うことで、どうしたらいいんだと迷う時間が減ります。
SMACSSの”レイアウト”は、BEMでいうところの”Block”なんですが、何せBEMで命名していますので、全てlayout.scss内に書いても辻褄があいます。
SMACSSのthemeを使わないのも、BEMの”Modifier”があるからです。
そして、これも全部”layout”に書いてしまうことにしてしまえば(もしくは、ページごとに分ければ)、シンプルですっきりしますし、SMACSSのメリットを失いません。
逆に、BEMの命名が成り立たないもの、単独で使う汎用クラスは”モジュール”にカテゴライズするとすれば、わかりやすいと思います。
おわり
SMACSSについては少し我流な部分がありますが、BEMもSMACSSも別にそうしなきゃいけないというルールがあるわけではなく、あくまでガイドラインなので、お互いのいい部分を組み合わせ、楽に、そしていい感じのCSS設計ができるようにしましょう。
時間をかけずに、しかも苦しまずに、いいものを作れたら最高ですよね。
それでは、ビクトリーなCSS設計を!
バイバイ~
CSS設計完全ガイド ~詳細解説+実践的モジュール集