好きなだけかりんとうを食べる人生

フロントエンドとかデザインとかバックエンドとか浅く広く。社会人3年目のうぇぶでぃれくたーです。

理想的なCSSの設計について

ついこの間仕事でクソみたいなcss書いて修正時に死んだ経験を踏まえて、設計をしっかり勉強することに。

現行のCSSが持つ問題点

定義が全てグローバル扱い

スコープ?なにそれおいしいの?

<div class="alert-btn">
  <a href="#">送信する</a>
</div>
.alert-btn a {
  text-decoration: none;
}
a {
  text-decoration: underline; /* 詳細度の関係上、上書きされない */
  color: #fff; /* CSS見てから上書き余裕でした^^ */
}

HTMLへの依存度が高い

特に要素セレクタを使うと依存度が高くなり、破綻しやすくなる傾向にある。

<div class="sample">
  <h1>これはサンプル</h1>
</div>
.sample h1 {
  font-weight: bold;
}
h1 {
  font-size: 14px;
}

このケースにおいてhtmlの構造が以下のように修正された場合、

<div class="sample">
  <h2>はサンプル</h2>
</div>

.sample h1は適用されなくなるため、その都度cssを変更する必要が出てくる。 もし他のページで同じスタイルを適用していた場合は、その適用箇所にも変更の影響が出る。 サンプルの時点でかなりめんどくさいのに、これが規模の大きな案件だったらキツい。てか死ぬ。

修正した時の影響範囲が大きい

プロジェクトの規模にもよると思うけど、特に汎用的なクラスはヤバい。

エラー吐かない

これはプリプロセッサ使えば解決する(たぶん)。

これらの問題点を解決するために考案されたのが以下のOOCSSである。

OOCSS

Object Oriented CSS
略してOOCSS。オブジェクト指向CSS。 ↑で挙げたような問題点を解決し、保守性・再利用性・拡張性・予測のしやすさを高めるためのアプローチ。

すごい乱暴な言い方になるけど、ページ内に存在するパーツをパターン毎に組み上げて分割することで、ブロックを組み立てるようなニュアンスでコーディングする、といったイメージ。 ボタンなどの例がわかりやすいかもしれない。

<div class="btn primary">送信する</div>
.btn {
  /* ボタンとしての最低限の機能 */
}
.primary {
  /* スタイル */
}
.secondary {
  /* スタイル */
}

体感だけどオブジェクト指向言語→HTML,CSSの順で勉強してきた人に多い気がする。 コツは

  • 共通する根本的な機能を抜き出すこと
  • 場所に依存しない設計を心がけること

の2つ。

SMACSS

Scalable and Modular Architecture for CSS
略してSMACSS。 CSSの弱点である保守性やメンテナンス性を高めつつ、デザインを統一させることでユーザー体験を一貫させ、UXの向上を図る。
OOCSSを実現するスタイルガイドの一種。

具体的には、

  • Base
  • Layout
  • Module
  • State
  • Theme

の5つのカテゴリーにCSSを分割し、管理する。

Base

サイト全体におけるデフォルトスタイル。
ここでデザインの詳細部を実装することは避ける(デザインはModuleが担当する)。
normalize.cssを採用してるとこが多い気がする(体感)。
自分は今までcompassreset.css使ってたけどnormalize.cssに乗り換えようか検討中。
多分慣れの問題。

Layout

そのまんま。ページを構成するパーツのレイアウトはここに。
marginpositionなどはここに該当する。
具体的にはheaderとかfooterとかの配置はここに記述することになる。
headerもfooterもユニークな要素だからId使ってもいいけど、使うと詳細度の関係上大抵めんどくさくなるので個人的には非推奨。

.l-header {}
.l-footer {}

って感じでプレフィックス付けると管理しやすくなる。

Module

ページ内において再利用可能なパーツのこと。
ボタンだったりリストだったり、ページを構成するほとんどの要素がここに属する。
Layoutの項でheaderとfooterのレイアウト情報を記述したけど、ここではそれらのデザイン部分を記述する。
ここで大切なのは、再利用のしやすさ保守性の高さ

State

そのまんま、コンテンツの「状態」。
JavascriptでDOM操作する際に主に使用する。

.is-active {
  display: block;
}
.is-hidden {
  display: none;
}

こんな感じで書けばイメージしやすいと思う。

Theme

テーマ。
サービスによっては、ユーザーが色を自由に切り替えるものがあると思うけど、多分それ用(自分もよくわからない)。
Moduleの色をここに記述する人もいるみたいだけど、これは人によって大分扱いが違うみたい。
個人的には色はModule内でSassの変数を利用して一元管理したい。

OOCSSとの違い

最大の違いは、SMACSSにはクラス名の抽象度に対するアプローチ(命名規則)が備わっているということ。
OOCSSで挙げた例で、.primaryとか.secondaryっていうクラス名があったけど、これは抽象的過ぎてページ内で衝突する可能性が非常に高い。

だからSMACSSのModule内では、

<div class="btn btn-primary">送信する</div>

こんな形で記述する。

BEM

命名規則の設計方法のひとつ。

  • Block
  • Element
  • Modifier

の3つにコンポーネントを分解し、それぞれの役割に従って命名する。略してBEM。
(個人的に)CSSで1番難しいのが命名規則
BEMに従えば命名もすんなり終わるっちゃ終わるんだけど、やっぱりめんどくさい部分もある。
初見だとめっちゃ気持ち悪い。
.Block__Element--Modifierといった流れでクラスを命名するので、後述のマルチクラスと併用するとHTMLがとんでもないことになる。
また、BlockやElementによっては名前が2単語で構成されるケース(.page-titleとか)もあるけど、そういった場合は.page-title__heading--titleのようなかなり見通しの悪いクラス名になる恐れがある。

SMACSS+BEM導入時の疑問点

  • 階層が深くなった時の処理 →深くなる時点で設計が破綻している可能性がある ElementのElementをわざわざ書く必要はない? (参考:いまどきのCSS – OOCSSとかBEMとかSMACSSとか)

  • 無駄にコードが増えそう 例:1箇所でしか利用しないコードをモジュール化する

  • どのタイミングでネスト構造を利用すべきなのか →モジュール化、コンポーネント化がしっかりされていれば自然とネストはそれほど深くならない(はず)

  • HTML汚くなるよね… →これは多分cssの簡潔さとのトレードオフ

  • クラスだけだとJSのパフォーマンス落ちるべ →フックにId使えや

OOCSS,SMACSSの問題点

  • クラスがセマンティックでなくなる
    →クラス名が抽象的になり、コンテンツの中身と結びつきが弱くなる
  • クラス名が増える →HTMLが汚れる

シングルクラスとマルチクラス

シングルクラス

  • HTML:きれい
  • CSS:きれいじゃない
  • BEMとの相性:よい

マルチクラス

  • HTML:きれいじゃない
  • CSS:きれい
  • BEMとの相性:よくない Javascriptのフックとしても使いやすいので個人的にはこっちの方がすき

SMACSS + BEM = 最良解というわけではない

SMACSSとBEMを導入することで、オブジェクトごとにスタイルを管理できるようになるため、スタイルの衝突は減少する。 同時に保守性も向上する。

しかし、なんでもSMACSSやBEMでおk…というわけでもない。 例えばLPをコーディングする時にコーダーに求められるものは、

スピード>デザインの再現度>>>保守性

である。 こういうケースではスタイルガイドを導入することによって開発スピードが落ちる恐れがあり、メリットもそれほど受けられない。

SMACSSを厳格に守る必要はなくて、各自の開発スタイルに合わせて調整するのがベストっぽい?

個人的なcss設計時のルール(草案)

いいなーって思った部分を集めてみた。

  • マルチクラスを採用
  • JavaScript参照用のclassはいらない(マルチクラスを採用してるから)
  • 細かい微調整系
  • text-align: center;
  • margin-bottom: 5px;
    →これらはhelper.scssにぶちこんで利用する
  • モジュールには位置情報を記述しない(再利用性を高める)

一番大事なのは「どのガイドラインを使うか」ではなく、「ルールを決めて実装する」ということ。
「HTMLの構造に依存しない」っていう方針はAngularJSと通ずるものがあって、非常に勉強になった。
とはいえもっとコード組まないと見えてこないものもあるので、これからもこの辺りは意識して設計していきたい。

さいごに

この本めちゃめちゃ参考になりました。
Web制作者のためのCSS設計の教科書 モダンWeb開発に欠かせない「修正しやすいCSS」の設計手法