ヘッダーの設計を考える

各部品にBlock名を付ける

ヘッダーは、ヘッダー・ロゴ・ハンバーガー(SPのみ)・グローバルナビの4つの部品から構成されているので、素直にそれぞれに対してその部品の役割をBlock名として付けておく。

<header class="header">
 <div class="logo"><a href="/">###</a></div>
 <button type="button" class="hamburger">~</button>
 <nav class="gnav">~</nav>
</header>

BlockかElementか?

Blockには大まかに2種類あると考えると判断しやすい。

  1. 明らかにそれ自体に明確な役割・機能を持つ部品
  2. 様々な場所で繰り返し利用される汎用的な部品

1は必ずしも繰り返し利用されるとは限らない。例えばサイトのヘッダーは各ページ1箇所にしか存在しないし、他の場所で再利用されることもないが、「ヘッダー」という独立した機能を持つ領域であるため、これはBlockとなる。ハンバーガーやグローバルナビといった部品もこれに該当する。
2は例えば見出しやボタン、アイコン、汎用的なリスト表示など様々な場所に配置され何度でも繰り返し再利用される部品である。サイトのロゴはヘッダーだけでなく比較的様々な場所に配置されるものなのでBlockとすることが可能。ただし本当にそれ単体でどこででも使い回せるようにしておくべきかはデザインによるところも大きいので、ヘッダーのみで使用するものとしてElementと定義するのも妥当な判断だと言える。

BlockでありかつElementでもある場合

Blockの中に他のBlockが入れ子になっている場合、特定の親ブロックの中に配置された場合だけスタイルを少し追加・変更したいといったケースはよくある。こうした場合には、header__logoというElementとしてのclassを重ね付けし、ヘッダーの中に配置された場合だけの特別なスタイルはそちらに指定しておくようにする。このようにしておくことで、使い回しのできる独立したロゴBlockのスタイルに影響することなく、特定の部品のElementとしてのスタイルを追加できる。
このようにBlock自身のスタイルと、特定のBlock内に配置された場合のレイアウトのスタイルを分けて考えると、部品の独立性を保ちながら様々なレイアウトに応用できるようになる。

<div class="logo header__logo"><a href="/">###</a></div>

ハンバーガーボタンを命名する

ハンバーガーボタンは、hamburgerという親Blockの直下のElement(span要素)の中に、更に孫要素の部品が入れ子になっている。実際にマークアップしていると[親 – 子]という単純な構造だけでなく、孫要素、ひ孫要素といった具合にどんどん階層が深くなっていくことはよくある。BEMではBlockの入れ子は許可されているが、Elementの入れ子は許可されていない
また、hamburger__innerに該当するspan要素を独立した新たなBlockとして以下のようにすることもこの場合は適切ではない。なぜなら.hamburger直下のspan要素はあくまでハンバーガーボタンを構成する部品の1つであって、それ単体で成立するものではないからである。
つまり、Element部品については子要素でも孫要素でも命名的にはすべて親ブロックに直接所属するElementとして表記すれば良いということである。

<button type="button" class="hamburger">
 <span class="hamburger__inner">
  <span class="hamburger__line"></span>
  <span class="hamburger__txt">MENU</span>
 </span>
</button>
【NG例1】
<button type="button" class="hamburger">
 <span class="hamburger__inner">
  <span class="hamburger__inner__line"></span>
  <span class="hamburger__inner__txt">MENU</span>
 </span>
</button>

【NG例2】
<button type="button" class="hamburger">
 <span class="hamburger-inner">
  <span class="hamburger-inner__line"></span>
  <span class="hamburger-inner__txt">MENU</span>
 </span>
</button>

グローバルナビを命名する

gnav直下のul要素にはElementとしてgnav__listと命名しておく。nav要素の直下にはul要素だけが入るとは限らないし、BEMの命名規則を積極的に破る理由もないからである。
BEMの規則では要素に直接スタイルを指定することは禁止されているため、その下のli要素・a要素にも必ずclass名を付けてclassセレクタでスタイルをコントロールする必要がある。
classを付けずに直接スタイルを指定した場合、開発途中でメニューが2階層のドロップダウンメニューに変更された時にul要素が入れ子になって下層メニューにもスタイルが影響するため、スタイル指定が煩雑化する。また、メニューの要素は必ずしも常にaタグであるとは限らず、一部のメニューだけクリックしたら下層を開く、といった挙動にしたい場合、そのメニューは遷移させるのではなく開閉のための機能ボタンとなるので、button要素でマークアップした方が適切である。aタグに直接スタイルが指定してあると、事情があって別の要素に差し替えた場合、スタイルが全く適用されなくなってしまう。

<nav class="gnav">
 <ul class="gnav__list">
  <li class="gnav__item"><a href="#" class="gnav__link">###</a></li>
 </ul>
</nav>

要素に直接スタイルを指定してはいけないのか?

CSS設計で重要なのは、なぜそのルールが設定されているのか、ルールを破った場合にどのようなリスクが発生するのかをきちんと把握することである。もし案件特性上それが許容できる範囲なのであれば、敢えてリスクを取ってその場の開発効率を優先するという判断があってもそれはそれで良いと思われる。特に小~中規模のWeb制作案件の場合は、特定の部品の中でしか使わない、変化する可能性がほとんどない限定された要素に関してはclassを付けずに子・子孫セレクタでスタイル指定することを許容したとても、実害はほぼないだろう。例えばシンプルなヘッダのグローバルナビに関しては

  • 基本はBEMの命名規則に則っている
  • あらかじめデザインが固まっている
  • あちこちで使い回す部品ではなく、一度決めたらめったなことでは変更されない
  • ul要素はHTMLの文法で直下の子要素がli要素に限定されている

という特性があるので、li・aにはclassを付けずにシンプルにマークアップしておき、CSSでは子セレクタで影響範囲を限定しておけば実害は少ないものと思われる。

<nav class="gnav">
 <ul class="gnav__list">
  <li><a href="#">メニュー1</a></li>
  //省略
 </ul>
</nav>
gnav__list > li {…}
gnav__list > li > a {…}
inserted by FC2 system