IDを使わないCSSの設計

CSSのスタイリングではIDを使用しない、という話をよく聞くようになりました。
私も最近は、IDを使わずにコーディングしているので所感を書きます。

CSSでIDを使わない

「IDを使わない」ということをHTMLの変化で示すと、以下のようになります。

<div id="header" class="clearfix">
  <h1 id="logo"><a href="">logo</a></h1>

  <ul id="heaeder-info">
    <li class="about"><a href="">about</a></li>
    <li class="sitemap"><a href="">sitemap</a></li>
  </ul>
</div>

↓↓↓↓

<div class="header clearfix">
  <h1 class="logo"><a href="">logo</a></h1>

  <ul class="heaeder-info">
    <li class="about"><a href="">about</a></li>
    <li class="sitemap"><a href="">sitemap</a></li>
  </ul>
</div>

IDだったところが、すべてclassに置き換わっています。IDを使うことに慣れていると気持ち悪いソースですね。私もこのソースを初めて見た時は、違和感しかありませんでした。

しかし「必ずしもIDとclassを使用しなければならない」という決まりもありませんし、IDがなくてもスタイルを適用できます。

パフォーマンス的にclassを使用するよりもIDを使用する方が早いともいわれていますが、モダンブラウザのセレクタの読み込みが向上しており、IDやclassを比べてもそれほど差はでないでしょう。パフォーマンスを考えるのであれば、もっと別にやることがあるはずです。

これらは引き算的な考え方ですが、IDを使用しないメリットがいくつかあります。

スタイルを使いまわす

CSSは、文章と装飾を分離させる理念の元に提唱された仕様の一つです。
10年以上前まではよく使用されていた centerタグ や fontタグ も、CSSの普及に伴い、出番が非常に少なくなりました。

center, fontタグを使用した例

<center><font color="red" size="small">red</font></center>
<font color="blue" size="large">blue</font></center>
<center><font color="red" size="small">red</font></center>
.
.
.
<center><font color="red" size="small">red</font></center>

CSSを使用した例

<style>
  .red {
    color: red;
    font-size: small;
    text-align: center;
  }
  .blue {
  	color: blue;
  	font-size: large;
  }
</style>

<div class="red">red</div>
<div class="bule">blue</div>
<div class="red">red</div>
.
.
.
<div class="red">red</div>

文章と装飾を分離させることによって、ページ内の見栄えから、サイトの全体の装飾の管理が容易になりました。
なぜなら、CSSはスタイルを共通化して、様々な箇所に振り分けることができるからです。

IDとclassのどちらも、サイト内の様々な箇所でスタイルを定義することができます。しかしページ単位で考えた場合に、IDのついたスタイルは1度しか出現させることができません。
ページ内で似たIDのスタイルを使い回したい場合は、以下のように複数のセレクタを繋がなくてはなりません。

/* SCSS
#header {
  width: 48em;
  margin: 0 auto;
}
#contents {
  @extend #header;
}
#footer {
  #footer-inner {
    @extend #header;
  }
}
*/

#header,
#contents,
#footer #footer-inner {
  width: 48em;
  margin: 0 auto;
}

複数のセレクタを繋げるならまだいいですが、同じようなスタイルを分散して記述されているのを、たまに見かけます。
セマンティックなCSSを意識することも大切かもしれませんが、同じスタイルを分散させて書いてしまったために、修正の手が増えた、という経験はないでしょうか?

汎用性の高いスタイルを抽出して、1つのclassにまとめてみましょう。
複数のIDよりも、1つのclassの方がCSSにとって管理・適用がしやすい場合があります。

.box-module {
  width: 48em;
  margin: 0 auto;
}

CSSの優先度

CSSは、上から読まれ、後に記述されたプロパティに追加、上書きされる仕組みになっており、セレクタに優先度が決められています。

!important > インラインCSS > ID > class > 要素 > 全称セレクタ(*)

優先度に関する情報は、さらに擬似要素や擬似クラスなどもあります。 もし定義したCSSを上書きしようと思うと、これらの優先度に振り回される場合があります。

!importantやインラインCSS、全称セレクタ、そしてIDを使用しないようにしましょう。

class > 要素

スタイルの適用手段を制限することによって、CSSの優先度が以前よりも単純になります。

IDとclassが混在して困る例

CSSは、設計に甘さがあると、ファイルサイズが肥大化していきやすくなります。
以下の例は、一見普通に見えますが、イレギュラーなスタイルを容易に適用できません。

<h2 id="main-title" class="about-title">タイトル</h2>

<style>
#main-title {
  font-size: 2em;
  padding-bottom: 4px;
  border-bottom: 1px solid #000;
}

/* イレギュラーなスタイル */
.about-title {
  border-bottom-color: #f00; /* #main-titeの優先度が強く、上書きできない */ 
}
</style>

IDに共通スタイルを適用してしまうと、イレギュラーなスタイルを後から適用しようとしても、優先度が邪魔をしてスタイルを正確に反映することができません。
この例に対して、正常なスタイルを上書き・適用するにはいくつかのパターンが存在します。

先ほどのIDとclassが混在しているスタイルを正常に適用するパターン

/* パターン1 - !important */
#main-title {
  font-size: 2em;
  padding-bottom: 4px;
  border-bottom: 1px solid #000;
}

.about-title {
  border-bottom-color: #f00 !important;
}


/* パターン2 - IDのセレクタを加える */
#main-title {
  font-size: 2em;
  padding-bottom: 4px;
  border-bottom: 1px solid #000;
}

#main-title.about-title {
  border-bottom-color: #f00;
}


/* パターン3 - 新たにIDを用意する */
#main-title,
#main-title-about {
  font-size: 2em;
  padding-bottom: 4px;
  border-bottom: 1px solid #000;
}

#main-title-about {
  border-bottom-color: #f00;
}


/* パターン4 - ID付の親要素を追加する */
#main-title {
  font-size: 2em;
  padding-bottom: 4px;
  border-bottom: 1px solid #000;
}

#main .about-title {
  border-bottom-color: #f00;
}

紹介したパターンは、セレクタの流れが変わってしまうため、どれも気持ちのいいものではありません。IDの付いたCSSを上書きや書き換えを無理に行おうとすると、CSSを肥大化させる要因にもなります。

全てclassにした例

classなら、この優先度の煩わしさを軽減できます。

<h2 class="main-title about-title">タイトル</h2>

<style>
.main-title {
  font-size: 2em;
  padding-bottom: 4px;
  border-bottom: 1px solid #000;
}

/* .main-title のイレギュラーなスタイル */
.about-title {
  border-bottom-color: #f00;
}
</style>

使用するセレクタを制限することによって優先度の深度が浅くなり、上書きが楽になります。セレクタの流れを乱すことなく、スタイルを適用させることもできます。
将来的にCSSが肥大化してしまっても、多くのセレクタをフルで使用している時よりも、優先度で頭を悩ませる時間を軽減させることができるでしょう。

スタイルと機能の分離

この話はCSSの話で、「HTMLでIDを使うな」という話ではありません。
IDは、HTMLのアンカーとして利用したり、JavaScriptのような「機能」に使用されるべきです。

CSSでIDを使わないようにすると、「class = 装飾」「ID = 機能」として、HTMLのIDとclassの住み分けを、はっきりさせることができます。

JavaScriptでclassを使用したい場合は、.js-などの接頭辞を付けて対応する方法もあります。

IDを使わないことは、表面的な問題でしかない

単にIDをclassに変えたからといって、劇的にCSSが扱いやすくなることは決してありません。 IDを使わないことに利点はあると思いますが、それは表面的な問題です。
もし子孫セレクタが平気で、5, 6個と出てくるようなCSSならば、IDやclassでもどちらでも構いません。 classだけでCSSを書くのであれば、それに適合したCSSの設計に見直さなければ意味がありません。

IDを使い続けるにしても、ID, class混在の適用パターンのようなセレクタにならないように心がけるべきです。

具体的に、気を付けるポイントは「コンテンツ部分」だと思います。
ヘッダーやサイドバーのスタイルは、よほど奇抜なデザインでない限り、1度作ってしまえば何とかなります。
しかしコンテンツは最も変化が多く、CSS肥大化の温床になりやすいところです。
CSSをコーディングする時は、ページ単位で考えるよりも、サイト全体の共通スタイルを見出しつつ、固有のスタイルをしっかりと適用していく方法があることも覚えておくといいかもしれません。