読者です 読者をやめる 読者になる 読者になる

美味しいものが食べたい

食べてる時と寝てる時が幸せ

BEM

会社のCSSの設計はBEMとSMACSSの融合体だとのことだったので なんとなく眺める程度では理解してたのですが、いざ書き手になるとなるとちゃんと知っとこうと思い勉強。

てことでBEMから。

今裏っかわで、デザインファイルを落としていて操作の反応がにぶすぎてイライラしてます。

BEMってなんぞ?

まさに優秀なまとめがこちらにありますので、こちらを参考にしていただければわかるはずかと。

github.com

わたしは上記をベースに、改めて自分で理解するためにまとめます。

BEMとは

BEM とはブロック(Block)、エレメント(Element)、モディファイア(Modifier)の略語である。 プログラミングにおける方法論の最も一般的なものはオブジェクト指向プログラミング(Object-Oriented Programming)だろう。 その枠組みは多くの言語で具体化されている。 BEMはいくつかの点でオブジェクト指向プログラミングと似ている。 それは現実のものをコードとして表現する方法であり、一連のパターンであり、また使用しているプログラミング言語とは関係なくプログラムの本質について考える方法である。 私たちはBEMの原則をフロントエンド開発のテクニックとツールをつくり上げるために用いたことで、Webサイトを迅速に開発し、長期間に渡ってメンテナンスし続けることができるようになった。

わたし、JSやりながらオブジェクト指向という言葉とはいつも戦ってきたんですが 数年経って改めてオブジェクト指向ってなんぞ?と振り返ってこちらで基礎を勉強しなおしました。

5分で絶対に分かる:5分で絶対に分かるオブジェクト指向 (1/6) - ITmedia エンタープライズ

さらに基礎パート

ここから始めるオブジェクト指向(1):オブジェクト指向の考え方 - ITmedia エンタープライズ

もっとオブジェクト指向に浸りたい人

オブジェクト指向の世界(1):流れ去るものと不変なもの - ITmedia エンタープライズ

やることができて、わたしは基礎パートあたりまでやったのですが、身近なものを題材に関係性を考えるのでなんとなく頭の中で理解はできます。 でもこれもだけど、実務で既に経験したうえでのほうが理解力は高くなるかと思われます。

自分で復習するためにも貼っとく。

ブロック(Block)

ブロックは独立した存在で、アプリケーションの「構成要素」である。 ブロックには単体のものも複合物(他のブロックを含むもの)もある。 例えばだけど、headerとかfooterとかmainとかtabとかdivでくくる大枠みたいなやつ。もちろんheaderの中のmenuだったり。 この辺は参考の図解みたほうがわかりやすい。

エレメント(Element)

エレメントは、ブロックの一部分であり特定の働きを持つ。 エレメントは文脈依存であり、そのエレメントが属するブロック内でのみ意味をなす。

日本語って難しいよね。上記だとまったくわからん。

f:id:pipipipipo:20161127230841j:plain

てことで、Qiitaのheaderをひっぱってきました。 この画像全体がblockで、ロゴと検索フォームとその横のラベル&テキストが1つのブロック且つ、各々block。 さらに、このラベル&テキストblockのラベルとテキストがelementです。

ページとテンプレートを表現する手段

ブロックとエレメントはページコンテンツの構成要素となる。 単にページ上に存在するということに加えて、それらの配置も重要である。 ブロック(またはエレメント)は、決まった順序でお互いに並ぶことができる。

f:id:pipipipipo:20161127232017j:plain ex.枠線で囲まれたのがblockとなり繰り返されている。

ブロックはその内部に他のブロックを含むこともできる。

f:id:pipipipipo:20161127230841j:plain ex.headerという大枠のblockの中にleftとrightのblockさらに、その中にlogo、search-form、label+textとかのblock

これらの構成要素がある一方で、プレーンテキストでページレイアウトを記述することも必要である。 そのためには、すべてのブロックとエレメントはそれを識別するためのキーワードを持つ必要がある。

特定のブロックを指すキーワードはblock nameとなる。 例えば、menuはメニューブロックのキーワードとなり、headはヘッダーブロックのキーワードとなる。

特定のエレメントを指すキーワードはelement nameとなる。 例えば、メニューの各アイテムはmenuブロックのitemエレメントである。

ブロック名(block name)は、明確にどのブロックを指すかを表現できなければならないため、プロジェクト内で一意である必要がある。 同じブロックの唯一のインスタンスは同じ名前を持つことができる(訳注:シングルトン的な認識をするブロックの場合、ということと思われる)。 その場合、ある1つのブロックがページに2回(3回、4回、…)と表れる、と表現することになる。 エレメント名はそのブロックのスコープ内で一意である必要がある。 エレメントは何度も繰り返すことができる。

f:id:pipipipipo:20161127232818j:plain

ソースみたら、div.a-boxってのが繰り返されてるのがわかる。 photoshop使いたくなかったけど、使ってしまった…

ブロックの独立

プロジェクトの成長にともなって、ブロックは追加され、削除され、ページの別な位置に移動されたりしていくものである。 例えばロゴと認証ブロックを入れ替えたり、メニューを検索ブロックの下に置いたり、といったことだ。 独立したブロックは、自由な配置(ページのどこでも、他のブロックを含んだり含まれたり)ができるような方法で実装されている。

んーつまり、配置を移動させたからといってレイアウトが崩れたりするのは違う。
だからblockってやつは独立した要素じゃないと駄目ってこと。
headerの中でこれとこれ入れ替えてもらえる?っってなった場合に、場所変えたから崩れたってのは駄目!

独立したCSS

これは、CSSの観点では以下のことを意味する。

* ブロック(やエレメント)は、CSSのルール内で使用可能なユニークな名前(CSSクラス)を持つ
* CSSセレクタにHTML要素などの、本質的に文脈フリーではないセレクタは含まない(.menu tdのような)
* カスケーティングセレクタは避けるべき

独立したCSSクラスのためのネーミング

適切なCSSクラス名のネーミングルールのひとつがこれだ:

  • ブロックのCSSクラスは、そのblock nameと同じ
<ul class="menu"></ul>
  • エレメントのCSSクラスは、任意のセパレーターで区切られたblock nameとelement name
<ul class="menu">
  <li class="menu__item"></li>
  <li class="menu__item"></li>
</ul>

カスケーディングを最小にするためには、エレメントのCSSクラスにブロック名を含めるのが重要である。 ツールやヘルパー(後述)が機械的にエレメントにアクセスできるようにするためには、セパレーターを一貫したものにしておくのも重要である。 私たちは、長い名前のセパレーターにハイフンを使い(block-nameなど)、ブロックとエレメントの区切りには2つのアンダースコアを使っている(block-name__element-name)。 好きなセパレーターを使うこともできる。

ex.
* block-name--element-name
* blockName-elementName

独立したテンプレート

テンプレートエンジンの観点からは、ブロックの独立は以下のことを意味する:

* ブロックとエレメントは入力データを表現しなければならない
    * ブロック(またはエレメント)は、「メニューはここに配置すべき」といったことをテンプレート内で表現できるようにするため、ユニークな「名前」を持たなくてはならない
* ブロックはBEMツリーのどこにでも出現できる

ブロックのための独立したテンプレート

テンプレート内にブロックがあらわれた場合、テンプレートエンジンはそれを一義的にHTMLに変換することができるはずである。 したがって、すべてのブロックはそのためのテンプレートを持つべきである。 例えば、XSLでのテンプレートはこのようになる:

<xsl:template match="b:menu">
  <ul class="menu">
    <xsl:apply-templates/>
  </ul>
</xsl:template>

<xsl:template match="b:menu/e:item">
  <li class="menu__item">
    <xsl:apply-templates/>
  </li>
<xsl:template>

ブロックの反復

あるブロックが単一のものとして開発されていたとしても、同じものをあらゆるタイミングでページに配置することができる。

CSS的に表現するとこうなる:
* IDベースのCSSクラスを使ってはならない
    * 「一意なものにはしない」という我々の要求を満たすため、クラスセレクタのみを使う。
JavaScript的にはこういうことだ:
* 同様の振る舞いを持つブロックは同様に検出される: それらは同じCSSクラスを持つ
    * CSSクラスセレクタを使うことで、動的な振る舞いを必要とする同じ名前のすべてのブロックを抽出することができる

xsl云々はいったん無視していいかも。ちょっと理解しがたい。

ブロックのためのモディファイア

既存のものと似ているが、見栄えや振る舞いが少しだけ違うブロックを作りたくなることはよくある。

こんなタスクがあるとしよう: * フッターに別なメニューを 異なるレイアウト で追加する。

既存のものとわずかしか違わないブロックを作るのではなく、モディファイアを使うことができる。 モディファイアは、見栄えや振る舞いが少し違うブロックやエレメントのプロパティである。 モディファイアは名前と値を持つ。複数のモディファイアは同時に使用できる。

例 背景色を指定するブロックモディファイア 「現在」のアイテムの見た目を変えるエレメントモディファイア

これはよくある!トップと下層でちょっとデザイン違うけど、同じ要素のものいれるみたいなやつ。
その時はモディフィアを使えってことね。

HTML/CSSの観点から

モディファイアは、ブロックやエレメントに追加するCSSクラスである。

<ul class="menu menu_size_big menu_type_buttons"></ul>
.menu_size_big {
  // 高さを指定するCSSコード
}
.menu_type_buttons .menu__item {
  // アイテムの見栄えを変えるCSSコード
}

エレメントモディファイア

エレメントのモディファイアも同じように実装される。 かさねて言うが、CSSを手書きする場合には、機械的にアクセスできるように一貫したセパレーターを使うことがとても重要だ。 例えば、現在のメニューアイテムは以下のモディファイアでマークアップできる:

<ul class="menu">
  <li class="menu__item">Index</li>
  <li class="menu__item menu__item_state_current">Products</li>
  <li class="menu__item">Contact</li>
</ul>

主題の抽象化

多くの人びとがプロジェクトで作業する場合、メンバーはデータドメインに関して合意を持ち、ブロックやエレメントの命名にはそのドメインを使うべきである。 例えば、タグクラウドブロックは常にtagsという名前になり、そのエレメントはtagとなる、というようなことだ。この決まりはCSSJavaScript、XSLなどすべての言語に対して同じだ。

開発プロセスの観点から: * すべてのメンバーは同じ用語を扱うようになる

CSSの観点から: * ブロックとエレメントに対するCSSを、命名規約に準じたCSSコンパイルされる擬似言語で記述することができる

.menu {
    __layout {
      display: inline;
    }
    __layout-item {
      display: inline-block;
      …
    }
    __item {
      _state_current {
        font-weight: bold;
      }
    }
  }

JavaScriptの観点から: * クラスセレクタを使ってDOM要素を直接探す代わりに、特別なヘルパーライブラリを使うことができる:

$('menu__item').click( … );
$('menu__item').addClass('menu__item_state_current');
$('menu').toggle('menu_size_big').toggle('menu_size_small');

ブロックとエレメントのCSSクラスの命名規約は時とともに変わるものである。 ブロックとエレメントにアクセスするのに特別なJavaScript関数を使い、その処理にはモディファイアを使うことで、命名規約が変わった場合でもそれらの関数を変更するだけでよくなる。

block('menu').elem('item').click( … );
block('menu').elem('item').setMod('state', 'current');
block('menu').toggleMod('size', 'big', 'small');

上記のコードは抽象的なものである。 私たちは実際には、bem-blブロックライブラリに含まれるi-bemブロックのJavaScriptコアを使っている。

http://bem.github.com/bem-bl/sets/common-desktop/i-bem/i-bem.en.html

このあたりは正直よくわからん。
jsどうのは無視しても、皆で共通認識のブロックやエレメントの命名規則を設けて使用しましょうということかな。

ブロックの一貫性

サイトには、ある動的な振る舞いを持ったボタンブロックがある。ブロックにカーソルを重ねた時、その見栄えが変わる。 マネージャーは、同じボタンを他のページでも使えるかどうか聞きたくなる。 ブロックのCSS実装だけでは不十分だ。 ブロックの再利用とは、JavaScriptによる振る舞いも再利用できるということを意味する。 ブロックは自身に関するすべてを「知って」いなければならない。 ブロックを実装するために、使用しているすべての技術を用いて見栄えと振る舞いを表現する。私たちはそれを多言語主義(multilingualism)と呼ぶ。 多言語(Multilingual)プレゼンテーションとは、ブロックの見た目と機能を実装するのに必要となるすべてのプログラミング言語でブロックを表現したものである。

ブロックをUI要素としてページに配置するには、以下のような技術でブロックを実装する必要がある:

  • ブロックの宣言をHTMLコードに変換するテンプレート(XSL、TT2、JavaScriptなど)
  • ブロックの見栄えを記述したCSS
  • ブロックが動的な振る舞いを持つ場合は、ブロックのJavaScript実装
  • 画像
  • ドキュメント ブロックを構成するすべてのものが、ブロック技術である。

以上。難しい。
超わかりにくい。理解力の問題なんかしら。笑

まとめ

・BEMという構造がある、それはBlock,Element,Modifier  
・要素をblockベースで考える。blockはblockを含む、blockに内包されるのがElement。  
・blockは独立した要素なので、他のblockに依存してはいけない。(配置を変更したからレイアウトが崩れるというのは駄目)  
・blockとelementについての命名は、blockはblock nameが使われる。どこでも使えるので、一意の名前であること。elementはblock name + element nameが使われる。  
・cssの記述でカスケーティングは使わない。(.menu tdとか)  
・idベースのcssの記述はしない。(#top > .menuとか)  
・要素は一緒で、見栄えや振る舞いだけが変わる時にはmodifier(blockやelementに追加するクラス)を使用する(背景色だけ違う、.currentの時の色が変わるなど)  

このあたりかな。
あくまでもこれをベースなので最高の理解力は必要ないと開き直る。
BEMだとクラス名が冗長化されすぎるしね。

まとめんの大変。
※余談だけど、Markdownで改行の仕方わからずだったけど、半角スペース×2で解決!