✌(‘ω’✌ )三✌(‘ω’)✌三( ✌’ω’)✌ CSSサイコ〜↑↑↑
miCSSは、RYO NAKAEがWebサイトのコーディングを行う時に使用しているCSSルールです。
OOCSS、BEM、SMACSS、知人友人などから影響を受けています。ちなみに読み方は自由です。
だいたい以下のルールを設けています。
- HTMLはLayout、Module、State、Modifierの4つで構成され、それぞれ接頭辞をつける
- 全てのタグにclassを設定する
- スタイルを当てるためにidは使わない
- JavaScriptで操作するclassは独立させる(スタイルを当てない)
- BEMっぽい命名規則にする
- Moduleは独立させる
- Sassなどでのネストは避ける
- グリッドシステムはHTMLに依存させない
- あまりルールにこだわりすぎず、無理な時は無理と諦める寛容な心を持つ
- 出来るだけ、出来るだけ…
タグにclassを設定する場合、必ずこの4つのどれかに分類します。
- ヘッダー
- セクション
などの、各要素を含む大枠
.l-header { ... }
.l-section { ... }
などのように、Layoutはl-
を接頭辞にします。
- ロゴ
- ナビゲーション
- タイトル
- ボタン
などの、Layoutに内包される各要素
例えばSMACSSではModuleには接頭辞をつけません。でも別に付けてもいいよね、と思ったのでModuleにも付けます。
.m-icon { ... }
.m-button { ... }
などのように、Moduleはm-
を接頭辞にします。
- ボタンのアクティブ時
- 四角いユーザーアイコンと丸いユーザーアイコン
- 1つだけ背景色が違うセクション
- トップページと下層ページでフォントサイズが違う見出し
などの、「わざわざModuleで分ける必要はないけど他と微妙に違う…」というような要素
文脈的に「一時的にこの状態(今はこうだけど途中で変わるかも)」というような要素に使います。
.m-navigation.is-fixed { ... }
.m-alert.is-hidden { ... }
などのように、is-
を接頭辞にします。
例えば、タブを切り替えた時にタブに.is-active
を設定するようなイメージです。
Stateとは違い、文脈的に「他の要素と恒久的に違う」というような要素に使います。
.m-button.m-button--large { ... }
.l-section.l-section--fullWidth { ... }
などのように、MindBEMdingのModifierの書き方を参考に、classの末尾に--modifier
というようにclass名を付けます。
例えば、「特定のセクションが色だけ違うけど、is-hoge
と命名するのはしっくりこない…」という微妙な気持ちの時に使います。
div {...}
やh1 {...}
といったスタイルの当て方は禁止します。出来るだけタグにclass名を付け、classに対してスタイルを当てるようにします。
###例外
.listItem a
というような、「どう考えてもこのa
タグはここでしか使わないだろ」というようなタグに関しては、例外的にclassを設定しなくても良いことにします。(流石にそこまで設定するの面倒すぎる)
idは強力すぎるので使いません。CSSで要素を指定する場合は全てclassで行います。
JavaScriptで要素を探す場合はidが速いので、使っても良いことにします。
要素をJavaScriptで操作する場合、
- 全くスタイルを当てていない
- 完全に独立した
上記2つのルールに沿ったclassを命名します。js-
というのがオススメです。
js-
という接頭辞を付けたclassを追加js-
という接頭辞を付けたidを追加
このどちらかにしておけば、CSSとJavaScriptが完全に独立するので良いと思います。
また、例えば.m-popup
に対して.js-popup
というクラス名を設定するのは、気持ち的にクラス名が独立してないのでやめた方がいいかも知れません。(と言いつつ代案が浮かばないので辛い)
BEMっぽい命名規則を採用します。
<div class="m-entry">
<h2 class="m-entry-title">記事一覧</h2>
<div class="m-entry-list">
<div class="m-entry-listItem">
<h1 class="m-entry-listItemTitle">エントリータイトル</h1>
<p class="m-entry-listItemText">エントリー本文</p>
</div>
<div class="m-entry-listItem">
...
</div>
</div>
</div>
このように子要素は親要素の名前を引き継ぐようにすると、class名の重複が防げます。Sassなどでネストする必要もなくなるので、良い感じのCSSが書けます。
この記事のように、子要素はキャメルケースで繋いでいけば、BEMあるあるなネストの深さも解消できるし、コードも見やすく、良い感じと思われます。
もちろん、さらにネストが深くなる場合もあると思われます。そういう場合は、「このパーツは再利用できるか?ならモジュール化しよう」などとモジュールの粒度を常に考えることが必要です。
BEMではなく独自ルールだと思われますが、CodeGridのモジュールリストは大変参考になります。
僕の中のゴーストが「ハイフンはModifierと見間違える」とささやくので、今後もしかしたらアンダースコアで繋ぐかも知れません。つーかBEMのアンダースコア2つはやっぱ視認性良い。
Moduleは独立させるようにします。
例えば、Moduleに横幅や高さを指定すると、他の場所では違う横幅で表示したいなどの不都合が出ます。なので、Module自体の幅や高さは出来るだけ指定せず、Moduleを囲むLayoutなどで指定するようにします。
SassなどのメタCSS言語でのネスト(入れ子)は避けるようにします。
.m-listItem {
&:first-child {
...
}
a {
...
}
}
こういうネストは、正直便利すぎて使わないと損な気がするので、使っても良いことにします。通常の記述でのネストは出来るだけ避ける。
個人的にサイトをグリッドに当てはめて作ることが多いので、グリッドシステムはよく使います。が、昨今のレスポンシブレイアウトの流行りなどにより、「従来のHTMLにclassを追加するタイプのグリッドシステム」はすぐに破綻してしまうということに気づきました。
.g-grid-6
などというグリッド用のclassを追加したとする- PCでの見た目的に、AとBという要素の両方に
.g-grid-6
を指定 - スマートフォンでは、要素Aは横100%にしたいけど、要素Bは横50%がいい…
- 破綻
という流れです。(最近これが多すぎて辛い)
こういう状況で理想的なグリッドシステムというのは以下のようなものだと思われます。
- HTMLではなくCSSに対してグリッドを設定できる
- Media Queriesに対応し、横幅に応じて要素ごとのグリッドを柔軟に再設定できる
- でもグリッドをぐちゃぐちゃにするのではなく、一定のルールを守る
これを満たすのは、thoughtbotのNeatだと思います。Neatを使うか、これを参考にmixinを自作するかすれば、HTMLに依存しない良いCSSが書けるのではないかと思います。
あまりルールにこだわりすぎると例外が発生した時に詰むので、その時は潔く諦める寛容な精神が必要です。
Rules of Threeという素晴らしい言葉があります。
例えばModuleを作る時なども、
- まずはひたすら親要素にネストして組む
- 別の箇所でまた同じ要素が出てきても、まだ我慢して親要素にネストする
- 3回同じ要素が出てきたら、初めてそこで子要素をModule化する(前2箇所も書き直す)
というようにすることで、いちいち「ここはModuleになるかな…いやどうかな…」などと悩まずに済むようになります。
Modifierの作り方や粒度というのもあると思っていて、例えば.button.button--large.button--red
などは果たして適当なのか、ということです。「それただのOOCSSやんけ」となってしまう場合が多いと感じていて、button.button--alert
などとするのが適当なのかなぁ、とは思いつつ、そうは言ってもパターン増えすぎるので細分化したい…という気持ち。