完璧を求めすぎて、平均以下な@It_is_Rです。
CSSは比較的簡単なものですが、CSS設計をしっかりしておかなければ、余分なコードが多くなったり、後から修正が大変になったりしてこまることになります。
コーディングルールには様々なものがありますが、その中にBEMというものがあります。
なかにはBEMを覚えたいけれども、情報が少なくて分からないという人も多いと思います。
そこで、今回はBEMというコーディングルールを学ぶと同時に、CSS設計を学んでいきましょう。
BEMとは
BEMは命名規則など、CSS設計の考え方のアイデアのことです。(構成案)
BEMはBlock, Element, Modifierの頭文字をとったものです。
公式サイトの文章を引用します。
BEM Quick start
BEM (Block, Element, Modifier) is a component-based approach to web development. The idea behind it is to divide the user interface into independent blocks. This makes interface development easy and fast even with a complex UI, and it allows reuse of existing code without copying and pasting.
訳)
BEM(Block, Element, Modifier) は、コンポーネントベースのWeb開発の手法である。その背後の考えは、独立したBlockとなったユーザーインタフェースに分けることができるということである。
これは、インタフェース開発が容易になり、複雑なUIでさえも速く、コピー&ペーストをしなくても現在のコードの再利用が可能になる。
CSS設計をする理由
まず、CSS設計をしておく理由を簡単に紹介しておこうと思います。
例えば、なにも考えずにHTMLとCSSを書いた場合を見てみましょう。
HTML
<header> <img src="img/logo.svg" /> <p>とことんフザケて、真面目にゲーム開発。</p> </header>
CSS
header img { width: 600px; height: 200px } header p { font-size: 16px; }
さて、かなり極端な例ですが、ヘッダー部分のパーツです。やはり、この例にはマズい部分が多くあります。
- img,pタグに、classを振らずにを直接指定している。
- headerタグの中のimg,pタグというように、依存関係になってしまっている。
このようにCSSを書いてしまうと、headerタグ内で別の画像を使用した時に、当然ながらその画像にもスタイルが適用されてしまいます。
では、これを改善するためにはどうすればいいのでしょうか。
これが正しいわけではないのですが、とりあえずclassを追加してみましょう。
HTML
<header class="header"> <img class="logo" src="img/logo.svg" /> <p class="description">とことんフザケて、真面目にゲーム開発。</p> </header>
CSS
.logo { width: 600px; height: 200px } .description { font-size: 16px; }
このようにすれば、ヘッダー内で別の画像を使用した場合でも、その画像にスタイルが適用されることはありません。
しかし、まだ問題はあります。
ロゴを使用するのは、本当にヘッダーだけでしょうか?
もしもフッターにロゴを使いたい時、クラス名はどうつければいいのでしょうか?
もちろん、logoというクラスを使用してしまった場合は、フッターのロゴにも同じスタイルが適用されてしまいます。
CSS設計をしっかりしておかないと、このように様々な問題に直面することとなります。
では、これからCSS設計をしっかりと見直していきましょう。
BEMの命名規則について
まず、BEMの命名規則について解説していきます。
BEMでは基本的にclassを使用し、idはほとんど使用しません。
BEMのクラス名は、Block, Element, Modifierの3つに分けて考えます。
基本的なクラス名は、2つまたは1つのアンダースコア、ハイフンで区切ります。
Elementの前には2つのアンダースコア(__)、Modifierの前には1つのアンダースコア(_)で区切ります。
また単語の区切りには、ハイフン(-)を使います。
Modifierのと区切りをハイフン2つ(–)とする表記を見かける場合があると思いますが、それはBEMをアレンジしたもので、実際に公式サイトで紹介されているのは、アンダースコアを使うものです。
block
block__element
block__element_modifier
block_modifier
これは基本の形です。
クラス名のつけ方にはルールがあります。
以下で詳しく解説しますので、順番に見ていきましょう。
Block
Blockはサイト内に存在する、独立したパーツのことです。
まず、公式サイトのBlockの説明を見てみましょう。
公式サイトの文章を引用します。
BEM Quick start
Block
A logically and functionally independent page component, the equivalent of a component in Web Components. A block encapsulates behavior (JavaScript), templates, styles (CSS), and other implementation technologies. Blocks being independent allows for their re-use, as well as facilitating the project development and support process.
訳)
Block
論理的かつ機能的に独立したページの構成要素(コンポーネント)、Web Componentsの要素に相当するもの。Blockは、振る舞い(JavaScript)、テンプレート、スタイル(CSS)、その他の実装技術を含む。Blockはそれらを再利用するために、独立して存在することを許し、同様に、プロジェクト開発を容易にし、進行をサポートする。
公式サイトでの説明でおおまかなことは理解できるかと思います。
では、細かく見ていきたいのですが、文章にすると分かりにくいと思いますので、大切な部分をリストにしてみました。
- Blockは、例えばヘッダーのBlock、ロゴのBlock、さらに、検索フォームのBlockなどが考えられます。
それぞれのBlockは、サイトにおいて独立したパーツと考えます。 - Blockは、Blockの中に作ることも可能です。つまり、入れ子構造にするということです。
ヘッダーBlockの中に、ロゴBlockを作るといった感じです。 - Blockは、後ほど紹介するElementとは違い、ページの中で様々な場所へ置くことができます。
ロゴと検索フォームの位置を入れ替えるなどの作業も、Blockとして考えれば分かりやすくなります。 - 同じBlockは何度も再利用することが可能です。例えば、ブログなどの記事のBlockは、日にちごとに沢山あります。
記事Blockのように、同じようなBlockを複数作成することも可能です。 - Block名は、そのBlockの役割にします。特徴などは名前に入れない様にしましょう。
また、複数の単語を区切りたい時は、ハイフン(-)を使用します。 - Blockの中には、必ずしもElementがあるわけではありません。
class名の例)
btn, button, menu, article, social-likes など。。。
ダメなclass名の例)
red, small など。。。
Element
Elementは、ブロックの構成要素です。
例えば、検索フォームBlockの中には、送信ボタンや入力フォームがあります。
それらがElementとなります。
ElementはBlockの構成要素なので、必ずBlockの中に存在する必要があります。
- Elementは、Blockの中にのみ存在できます。
- Elementのクラス名は、その役割を親となるBlockのclass名に(__)で繋ぎます。
- ElementもBlockと同様に入れ子にすることが可能ですが、block__element__elementの様な表記は間違っています。
- Blockのところにも書きましたが、Elementを持たないBlockも存在します。
また、BlockでありElementでもあるといった要素を作ることも可能です。
たとえば、ヘッダーBlockの中のロゴBlockは、ヘッダーBlockのElementですよね。
では、何がBlockで、何がElementなのでしょうか?
後ほど詳しく解説します。
class名の例)
menu__item, nav__list, article__title など。。。
ダメなclass名の例)
menu__item__link, button_primary__text, button__primary など。。。
Modifier
Modifierは、BlockやElementの状態や特徴を表すものです。
例えば、メニューの、今いるページの部分の色を変えたい、ボタンの大きさを変えたい、といった場合に使用します。
- Modifierは、単独で使うことはできません。必ず、BlockやElementと一緒に使ってください。
- ModifierをBlockやElementと一緒に使うことで、その見た目などを変更することができます。
- クラス名のつけ方は、親となるBlockやElementのclass名に、アンダースコア(_)で繋ぎます。
- Modifierには、Booleanとkey-valueの2種類があります。
まず、Modifierには、2種類のタイプがあります。
Boolean と key-value です。
Boolean は真偽を表すものです。つまり true か false かで表されるものです。
例えば、ボタンが無効か無効でないかなど、true か false で表せるものは Boolean を使用します。
例)
article__button_disabling, nav_nonexistenceなど。。。
key-valueは、「keyはvalueです」という形のclass名にします。
keyとvalueの間は、アンダースコア(_)で繋ぎます。
例)
button_color_primaryなど。。。
BEMを使ってボタンを作る。
では、BEMの手法を使って、ボタンを作ってみましょう。
HTML
<a class="btn" href="">Button</a> <a class="btn btn_color_primary" href="">Button</a> <a class="btn btn_color_danger" href="">Button</a> <a class="btn btn_size_large" href="">Button</a> <a class="btn btn_size_large btn_color_primary" href="">Button</a> <a class="btn btn_size_large btn_color_danger" href="">Button</a>
CSS
.btn { color: white; text-decoration: none; display: inline-block; border: none; background: #aaa; padding: 5px; } .btn.btn_color_primary { background: #00f; } .btn.btn_color_danger { background: #f00; } .btn.btn_size_large { padding: 10px 100px; }
See the Pen button-bem by R (@It_is_R) on CodePen.
上の例では、 .btn Blockに、 .btn_color_xxxx や、 .btn_size_xxxx という Modifier を当てています。
.btn はデフォルトのボタン、 .btn_color_xxxx といった Modifier を当てることで、ボタンの色を変えたり、サイズを変えたりといったことを可能にしています。
実際にBEMを使った設計をしてみよう
では、実際にBEMを使った設計をしてみます。
このブログのヘッダーをベースにした、HTMLとCSSを作ってみます。
まずは大まかなレイアウトを、BEMに沿って作ってみます。
HTML
<header class="header"> <a class="logo" href="">ORIGINAL-GAME.COM</a> <p class="blog-description">とことんフザケて、真面目にゲーム開発。</p> <ul class="menu"> <li class="menu__item"><a class="menu__link" href="">アイテム</a></li> <li class="menu__item"><a class="menu__link" href="">アイテム</a></li> <li class="menu__item"><a class="menu__link" href="">アイテム</a></li> <li class="menu__item"><a class="menu__link" href="">アイテム</a></li> </ul> </header>
CSS
.header { background-color: #00bcc6; } .logo { font-size: 30px; color: white; text-decoration: none; } .blog-description { font-size: 16px; color: white; } .menu { font-size: 0; } .menu__item { font-size: 20px; background-color: #16d6e0; display: inline-block; } .menu__link { padding: 5px; display: block; color: white; text-decoration: none; }
このソースを見て、.headerの中の.logoって、.headerのElementになるんじゃ。。。と思う人がいるかもしれません。
しかし、BEMではBlockの中にBlockを入れることは、許可されています。
公式サイトの文章を引用します。
BEM Quick start
●Blocks can be nested in each other.
●You can have any number of nesting levels.
訳)
●ブロックは互いに入れ子にすることができる。
●あなたは、入れ子を任意の階層数にしておくことができる。
また、このコードでは、ロゴ部分の上下左右の幅がつまってしまっています。
今回はサンプルなのでテキストを使用していますが、本来なら画像が入る部分です。
しかし、ロゴはサイト内で何度も再利用したいですよね。
特にロゴは、別の場所で余白なしのロゴが必要な時がもしかするとあるかもしれません。
では、ロゴブロックのスタイルは変えずに、余白を作ってみましょう。
HTML
<header class="header"> <div class="header__logo"><!--追加したコード--> <a class="logo" href="">ORIGINAL-GAME.COM</a> </div><!--追加したコード--> <p class="blog-description">とことんフザケて、真面目にゲーム開発。</p> <ul class="menu"> <li class="menu__item"><a class="menu__link" href="">アイテム</a></li> <li class="menu__item"><a class="menu__link" href="">アイテム</a></li> <li class="menu__item"><a class="menu__link" href="">アイテム</a></li> <li class="menu__item"><a class="menu__link" href="">アイテム</a></li> </ul> </header>
CSS
.header { background-color: #00bcc6; } /*追加したコード*/ .header__logo { padding: 10px; } .logo { font-size: 30px; color: white; text-decoration: none; } .blog-description { font-size: 16px; color: white; } .menu { font-size: 0; } .menu__item { font-size: 20px; background-color: #16d6e0; display: inline-block; } .menu__link { padding: 5px; display: block; color: white; text-decoration: none; }
この様に、.headerのElementとして、.header__logoで.logoを囲ってしまえば、ロゴに余白を与えることができます。
Mix ( Mixes )
Mix ( Mixes )というテクニックがあります。
恒例となった公式サイトの引用です。
BEM Quick start
Mix
A technique for using different BEM entities on a single DOM node.Mixes allow you to:
●Combine the behavior and styles of multiple entities without duplicating code.
●Create semantically new UI components based on existing ones.
訳)
Mix
1つのDOMノード上に、異なるBEMエンティティを使う為のテクニック。
Mixes は以下のことを許可する。
●振る舞いと、コードの複製でない多数のエンティティのスタイルを組み合わせる。
●現在あるものを基礎に、新しいUI要素を意味的に作る。
ヘッダー内のロゴに余白をつけた先ほどのコードを、Mix ( Mixes )を使って作り変えてみましょう。
HTML
<header class="header"> <a class="logo header__logo" href="">ORIGINAL-GAME.COM</a> 〜省略〜 </header>
CSS
.header { background-color: #00bcc6; } .header__logo { padding: 10px; } .logo { font-size: 30px; color: white; text-decoration: none; } 〜省略〜
このMixのテクニックは、独立したBlockである .logo と、 .header のElementである .header__logo を合体させたものです。
こうすることで、ロゴBlockは再利用可能なまま、paddingで余白を作ることができます。
See the Pen header-bem by R (@It_is_R) on CodePen.