12周年記念パーティ開催! 2024/5/10(金) 19:00

SMACSSによるCSSの設計 前編 ベースとレイアウト

CSSの設計方法のひとつ、SMACSS(スマックス)の基礎を学びます。今回はSMACSSの5つのルールのうち、ベースルールと、レイアウトルールを解説します。

発行

著者 山田 敬美 フロントエンド・エンジニア
SMACSSによるCSSの設計 シリーズの記事一覧

はじめに

SMACSSとは、Scalable and Modular Architecture for CSSの略語で、「スマックス」と読みます。

SMACSSはCSSの設計手法のひとつで、CSSのルールを5種類にカテゴライズした上で、それぞれの考え方や記述ルールが取り決められているのが特徴的な手法です。

SMACSSの考え方

CSSのカテゴライズ

SMACSSでは、CSSのルールを次の5つのカテゴリに分類しています。

  • ベース:要素そのもののデフォルトスタイル
  • レイアウト:ページをエリアごとに分割
  • モジュール:再利用可能なパーツ
  • 状態(ステート):レイアウトやモジュールの特定の状態を示す
  • テーマ:サイトのルック&フィールを定義

それぞれの具体的な解説は、以降で行います。

SMACSSで設計する目的

書籍『Scalable and Modular Architecture for CSS(日本語版)』では、CSSをカテゴライズすることの目的を『デザインの中で繰り返されるパターンを体系立てるため』と解説しています。

繰り返しのパターン化によるメリットとして、次のことが挙げられています。

  • コード量が少なくなる
  • メンテナンス性を高める
  • ユーザー体験の一貫性の向上

これらは、どんなサイトでもメリットとなるため、小規模から大規模までさまざまなサイトでSMACSSの考え方は有用であると言えるでしょう。

それではひとつひとつのルールを解説していきましょう。

ベースルール

ベースルールは、サイト全体で要素そのもののデフォルトスタイルを定義します。

ベースルールでは、主に次のセレクタを使ってスタイルを適用します。要素そのものの見た目を定義するという性質のため、IDやクラスは使いません。

  • 要素セレクタ(bodya
  • 属性セレクタ(input[type=text]
  • 擬似クラスセレクタ(a:hover

要素のデフォルトの見た目

bodyの背景や、リンクのデフォルトカラーや下線の状態、フォントスタイルなど、サイト全体での要素そのものの見た目は、次のように要素セレクタに対して定義していきます。

body {
  background: white;
}

a:link {
  color: blue;
}
a:visited {
  color: navy;
}
a:hover,
a:active,
a:focus {
  color: red;
}
...

ここで注意したいのは、要素セレクタに対してあまりにも具体的なスタイルを指定をしてしまうと、後々その要素を使った別の見た目のモジュールを追加したくなった場合に、ベースのスタイルをすべて上書きしなければならなくなるということです。

例えば、tableの場合、表組みのデザインが1パターンしかないからといって、tableタグ自体にそのデザインのスタイルを直接指定してしまうと、あとからパターンを追加するときに面倒です。tableの場合は、次のようにリセットのみにとどめておくと扱いやすいでしょう。

table {
  border-collapse: collapse;
  border-spacing: 0;
}

CSSリセット

CSSリセットもベースルールに含まれます。

body, div, dl, dt, dd, ul, ol, li,
h1, h2, h3, h4, h5, h6,
pre, code, form, fieldset, legend, input, textarea,
p, blockquote, th, td {
  margin: 0;
  padding: 0;
}
table {
  border-collapse: collapse;
  border-spacing: 0;
}
fieldset,
img {
  border: 0;
}
...

Normalize.cssreset.csshtml5reset.cssなどのCSSリセット用のライブラリを利用する場合も、SMACSSのカテゴリで分類するとすれば、ベースルールに属することになると考えられます。

レイアウトルール

レイアウトルールでは、ページのエリア分けを行います。

.l-header {
  margin-bottom: 20px;
}

.l-footer {
  border-top: 1px solid gray;
}

.l-main {
  float: left;
  width: 80%;
}

.l-sub {
  float: right;
  width: 20%;
}

レイアウトを独立したルールとすることで、ヘッダやコンテンツエリアなどのエリアを分けるためのパーツと、ダイアログやナビゲーションなどのページを構成するためのモジュールを、完全に分けて管理することができます。

プリフィックス(l- / layout-

レイアウトルールをクラス名で管理する場合は、モジュールルールや状態ルールとの区別をつけるために、プリフィックスをつけます。

サイト全体で共通していれば、どのようなプリフィックスでも自由ですが、公式で紹介されているl-xxxlayout-xxxとしておけば、誰が見てもレイアウトルールだと理解できそうです。

レイアウトへのIDセレクタの利用

IDセレクタはCSSの詳細度を高めてしまい、場合によってはCSSを複雑にしてしまうので利用する場合は注意が必要です。

ただし、ヘッダやフッタなどの主要なレイアウトは、慣習的にIDセレクタが使われることがあるため、SMACSSではレイアウトルールでIDセレクタを利用することを禁止してはいません。

コラム:IDセレクタのデメリット

ページ内アンカーやJavaScriptのフックとしてID名を利用する場合は別として、CSSの設計においては、すべてクラスセレクタの利用で統一してもよいのではないかと筆者は考えます。

CSSでIDセレクタを利用する場合、次のようなことを考慮する必要がありますが、クラスセレクタの利用であれば、このような問題を気にする必要はなくなるからです。

  • IDセレクタは仕様上、同じページ内で複数利用できない
  • IDセレクタはCSSの詳細度があがるため、スタイルの上書きが難しくなる

また、クラスセレクタのみと決めてしまえば、IDセレクタにするかクラスセレクタにするかで悩むこともなくなります。

レイアウトとモジュールを分離するメリット

レイアウトとモジュールを独立させることで、それぞれの再利用性がアップします。

ボックスが2カラムで横に並ぶレイアウトパターンを例として、その意味を具体的に考えてみましょう。

まずは、次のように、ボックスのデザインのスタイルと、カラム分けのためのスタイルを一緒に指定してみます。

HTMLとCSSは次のように書きました。

<div class="multicolumn">
  <div class="box">box1</div>
  <div class="box">box2</div>
</div>
/* ベースルール */
body {
  margin: 0;
  padding: 0;
}

/* モジュールルール */
.multicolumn {
  width: 480px;
  margin-left: -10px;
  *zoom: 1;
}
.multicolumn:after {
  content: "";
  display: table;
  clear: both;
}
.multicolumn .box {
  /* カラム分けのためのスタイル */
  float: left;
  width: 230px;
  margin-left: 10px;
  /* ボックスのデザインのスタイル */
  padding: 20px 0;
  background: #333;
  color: #fff;
  text-align: center;
}

これだけなら問題はなさそうですが、同じデザインのボックスを使って、レイアウトのパターンを増やす必要が出てきた場合に、困ったことになります。

まず、ボックスのデザインのスタイルと、カラム分けのためのスタイルが一緒に指定されているため、ボックスのデザインのスタイルのみを独立させて、汎用的に利用できるようにする必要があります。

また、レイアウトのパターンが増えるにしたがって(シングルカラムや3カラムなど)、CSSにそのつど追記しないといけないため、CSSのコード量がどんどん増えていってしまいます。

そこで、次のように、CSSグリッドシステム*の考え方を取り入れたレイアウトルールを作り、レイアウトとモジュールを完全に分離してみましょう。

*注:CSSグリッドシステム

あらかじめ指定した幅のグリッドを組み合わせることで、ページのレイアウトを構成していく手法です。代表的なものには、960 Grid Systemなどがあります。

HTMLにはレイアウト用のdiv要素を加え、boxモジュールとは分離されました。

<div class="l-container-12">
  <div class="l-grid-06">
    <div class="box">box1</div>
  </div>
  <div class="l-grid-06">
    <div class="box">box2</div>
  </div>
</div>
/* ベースルール */
body {
  margin: 0;
  padding: 0;
}

/* レイアウトルール */
.l-container-12 {
  width: 480px;
  margin-left: -10px;
  *zoom: 1;
}
.l-container-12:after {
  content: "";
  display: table;
  clear: both;
}
.l-grid-01, .l-grid-02, .l-grid-03, .l-grid-04, .l-grid-05, .l-grid-06, .l-grid-07, .l-grid-08, .l-grid-09, .l-grid-10, .l-grid-11, .l-grid-12 {
  float: left;
  margin-left: 10px;
}
.l-grid-01 { width: 30px; }
.l-grid-02 { width: 70px; }
.l-grid-03 { width: 110px; }
.l-grid-04 { width: 150px; }
.l-grid-05 { width: 190px; }
.l-grid-06 { width: 230px; }
.l-grid-07 { width: 270px; }
.l-grid-08 { width: 310px; }
.l-grid-09 { width: 350px; }
.l-grid-10 { width: 390px; }
.l-grid-11 { width: 430px; }
.l-grid-12 { width: 470px; }

/* モジュールルール */
.box {
  padding: 20px 0;
  background: #333;
  color: #fff;
  text-align: center;
}

これだけを見るとコード量が増えてしまったように思えますが、ページで利用するカラム分けのパターンが増えた場合も、このCSSグリッドシステムで補える内容であれば、CSSの記述がこれ以上増えることはありません。

例えば、組み合わせによって3カラムにでも4カラムにもできますし、それぞれのカラムの幅の割合を変更することもできます。

また、別のモジュールを同じようにカラム分けしたくなった場合も、このレイアウトモジュールを流用するだけですみます。

子孫セレクタの利用

基本的には、レイアウトルールでは、セレクタを単独で利用することが多いので、子孫セレクタを利用する機会は少ないです。

しかし、次のように、特定のレイアウトルールをbody要素などに付与し、全体のデザインを変更する使い方もあります。

.l-main {
  width: 80%;
  float: left;
}
.l-sub {
  width: 20%;
  float: right;
}

.l-fixed .l-main {
  width: 600px;
}
.l-fixed .l-sub {
  width: 200px;
}

この場合は、.l-fixedをbody要素などに付与することで、リキッドレイアウトのデザインから、固定レイアウト用のデザインに変更しています。

まとめ

今回は、SMACSSの5つのカテゴリである「ベース、レイアウト、モジュール、状態、テーマ」のうち、大枠となるベースとレイアウトについて解説しました。

次回は、大枠に収まりコンテンツを形作っていくモジュールと状態、サイトの全体的なイメージを調整するテーマについて取り上げます。