Edited at

破綻しにくいCSS設計の法則 15

More than 3 years have passed since last update.


  1. ブラウザスタイルは平坦化しておく

  2. リセットCSSはオプトアウト可能にしておく

  3. 登場頻度の高い組合せはplaceholderとして登録してから利用する

  4. 可能な限り画像はスプライト生成してから利用する

  5. それ以上分解不可能なコンポーネントは要素のように扱う

  6. コンポーネントは自己完結型のものを使う

  7. BEMはDRYになるよう粒度を下げる

  8. 可能な限り@extendは利用しない

  9. レスポンシブでない場所では、Utilitiesクラスを活用する

  10. shame.cssはいつも綺麗にしておく

  11. 詳細度または特異性の高いものほど後方に記述する

  12. 可能な限り!importantしない

  13. 可能な限りハックしない

  14. 変数をデザインガイドとして活用する

  15. CSSファイルを分割するメリットはほとんどないので一つにまとめる


1. ブラウザスタイルは平坦化しておく

例えば、こういうScrap & Buildは単に通信量のムダ。


reset.css

* {

font-weight: normal;
vertical-align: baseline;
}
b, strong {
font-weight: bold;
}
sub {
vertical-align: sub;
}

normalize.cssで平坦化した上で、さらに必要と思うリセットを施せばいいだけ。


2. リセットCSSはオプトアウト可能にしておく

例えば、箇条書きのスタイルを普通にリセットしてしまうと、本当に箇条書きとして使いたい時に困る。


css

ul {

margin: 0;
padding: 0;
list-style: none;
}

以下のようにリセットすれば、オプトインするかオプトアウトするかを都度選択できる。


css

.ul {

margin: 0;
padding: 0;
list-style: none;
}


オプトイン

<ul class="ul">



オプトアウト

<ul>


nondestructive-reset.css(非破壊的リセットCSS)なら、いつものリセットと同じ記述量で、二倍の選択肢が得られる。


3. 登場頻度の高い組合せはplaceholderとして登録してから利用する

二つ以上のプロパティをセットで書くことが多いのであれば、まずはplaceholderとして登録する。


sass

%link--tint

color: blue
text-decoration: none

.some-link
@extend %link--tint



stylus

link--tint()

color blue
text-decoration none

.some-link
link--tint()


出力結果はいずれも、


css

.some-link {

color: #00f;
text-decoration: none;
}

厳密にいうと、Stylusの方はplaceholderを@extendではなく@includeしているので、タイプ数も含めてStylusの方が優れている。@extendについては後述。


4. 可能な限り画像はスプライト生成してから利用する

background-repeatさせない画像であれば、原則スプライトにする。@extendやMixinを経由して呼び出すことで、記述量を最小限にできる。


sassで@extendする例

.foo

@extend .sprite--logo


stylusでmixinを利用する例

.foo

sprite("logo.png")

自動生成なら widthheightbackground プロパティなどを記述不要にできる。画像までのパスも不問で、ファイル名だけが分かればいい。


5. それ以上分解不可能なコンポーネントは要素のように扱う

Web Componentsのようにとは言いませんが、AngularJSのディレクティブやJadeのMixinを利用したカスタムタグなど、内部構造が容易に変更できないHTMLコンポーネントは、selectタグのようなHTML要素を扱うのと同様に扱う。

つまり、内部構造のスタイルを定義していいのは、そのコンポーネント自身だけ。


6. コンポーネントは自己完結型のものを使う

自己完結していないコンポーネントの例として、Bootstrapのnavbarfixedレイアウトの際に、他の要素へ依存するのでよくない。


問題箇所

body {

padding-top: 70px;
}

そう書いたのを忘れた頃に<div class="navbar">を取り除くページがあったりすると、辛い。こういうことが積み重なると、とても辛い。


解決方法

.navbar__wrapper {

height: 70px;
}

のように、自己完結型に修正してから利用する。


7. BEMはDRYになるよう粒度を下げる

BEMは、class名が長くなるので倦厭されることもありますが、まさにそこがBEMのメリットで、レイアウトのバリエーションが何百になっても「命名の衝突」を簡単に回避できます。(アンダースコア派かハイフン派か、といった宗教戦争を回避できるのもメリット)

ただし、Blockの粒度を適度に分割しないと全然DRYにならずに、記述量が増える一方なので注意が必要です。

例えば、


html

<ul class="list">

<li class="list__item">
<div class="list__item__header">

とするのもいいけど、


html

<ul class="list">

<li class="list__item card">
<div class="card__header">

のように、コンポーネント単位で委譲できると素敵。


8. 可能な限り@extendは利用しない

@extend@mediaは衝突する概念なので、レスポンシブ・デザイン等では併用が困難。


sass

%link--print

color: black
text-decoration: dotted

.some-link
color: blue
text-decoration: none

@media (print)
@extend %link--print


出力結果は意図しない形に、


css

.some-link {

color: blue;
text-decoration: none;
}

.some-link {
color: black;
text-decoration: dotted;
}


代わりに@includeを使えば大丈夫。


sass

@mixin link--print

color: black
text-decoration: dotted

.some-link
color: blue
text-decoration: none

@media (print)
+link--print



css

.some-link {

color: blue;
text-decoration: none;
}

@media (print) {
.some-link {
color: black;
text-decoration: dotted;
}
}


望んだ結果になりました。Stylusでも同様です。


stylus

link--print()

color black
text-decoration dotted

.some-link
color blue
text-decoration none

@media (print)
link--print()



9. レスポンシブでない場所では、Utilitiesクラスを活用する

UtilitiesクラスというのはCSS界のワンライナーのことです。


css

.hidden { display: none !important; }


HTML側に直接記述して利用するので、レスポンシブな部位とは相性が悪い。


間違った用法

<div class="sidebar hidden">


レスポンシブでない部分(状態変化がない部分)であれば、活用することでCSSの量を減らせます。


ここだけセンタリングしたい時

<h1 class="h1 section__title text--center">



css

.text--center { text-align: center; }


BEMを押し通すなら以下のようになりますが、厳格すぎるとDRYにならずにコード量が増えます。


html

<h1 class="section__title section__title--centered">



sass3.3・stylus

.section

&__title
&--centered
text-align: center

Utilitiesクラスは、大量に発行すると「命名の危機」を引き起こすので、拡張性を考えて作りましょう。globalize.cssというUtilitiesクラス専用のライブラリもあります。


10. shame.cssはいつも綺麗にしておく

shame.cssとは、綺麗にしておかないと恥ずかしいものを書く場所です。

レイアウト上のバグが見つかった時、一時しのぎなコードを書くのに使います。


_shame.sass

.page__footer

overflow: hidden // I don't know why but it fixes our problem.

overflow: hiddenされては困ると、別の誰かが文句を言うかもしれません。

$ git blame _shame.sass

解決したらしかるべき場所に移しましょう。


_page.sass

.page__footer

+clearfix


_shame.sass

// Keep this file clean.



11. 詳細度または特異性の高いものほど後方に記述する

書き順については、セレクタの詳細度またはスタイルの特異性を考慮しながら決める。


  • 詳細度の高いセレクタを上書きするためには、さらに高い詳細度が必要になり、それを上書きするために...となるので、まずは詳細度の高いセレクタを作らないこと。どうしても必要な場合は後方に書く。前方は最悪。

  • 特異性のあるスタイルを後ろに持ってくるということは、シンプルなスタイルほど先に書くということ。「デザインの解像度」を上げていくやり方のほうがうまく機能する。

いずれも「負の遺産」にならないように注意する。


12. 可能な限り!importantしない

// Unless it's a truly important.


13. 可能な限りハックしない

// There is always another way.


14. 変数をデザインガイドとして活用する

サイト内でバラツキが少ない方がデザイン的に良いとされるものがあります。これらは変数化して利用することでデザインガイドにもなり、デザイン変更にも強くなります。


  • 文字サイズ

  • 文字色

  • 背景色

  • フォントファミリー

  • そのほか定数となるもの


sass

$font--medium: 1rem

$font--small : 0.875rem

$color--text: #333
$color--link: #08c



stylus

$font--medium = 1rem

$font--small = 0.875rem

$color--text = #333
$color--link = #08c


また、Stylusは透過的に変数を処理できるので、さらにナチュラルにも書けます。


stylus

blue = #08c

.some-link
color blue


デザインガイドに従わない場合は変数名を使わずに定義します。


stylus

blue = #08c

.some-link
color #06c



15. CSSファイルを分割するメリットはほとんどないので一つにまとめる

やんごとなき理由がない限り、CSSは分割しない方がメリットが大きい。

やんごとなき理由


  • IEが許容するセレクタ数の上限に達した(4095個/1ファイル)

  • デザインのテーマがそもそも違う(例:サブサイト)

  • デバイス種別ごとにマークアップを出し分けていて、共通点が少ない

  • ユーザーがテーマファイルを切り替えられる

1ファイル化のメリット


  • HTTPリクエストを減らせる

  • 詳細度の管理が容易

  • ファイルのロード順に伴うトラブルがない

ブラウザからすればCSSはただの宣言書なので、CSSファイルが複数あっても上から順に評価されるだけ。分けることによる機能的なメリットはまったくない。まとめましょう。


16. 追記

最後までお読みいただき、ありがとうございました。

もう少しまとまった内容をこちらに追記いたしましたので、あわせて読んでいただけると幸いです。