こんにちは!LIGフィリピン支社代表のせいと(@seito_horiguchi)です。
皆様、CSS書いてますでしょうか。
今回はSMACSSやBEMをある程度ご存知の方向けに、コンポーネントをマークアップする際に役立つテクニックと題して、「SMACSSを使う際に役立つテクニック」「BEMを使う際に役立つテクニック」「さまざまなシーンで役立つテクニック」をご紹介したいと思います。
なお、SMACSSやBEMをご存知ない方は、本記事の参考文献&記事のリンクが参考になると思いますので、はじめにこちらをご参照いただければと思います。
※「コンポーネント」という言葉は、使われるシーンによってさまざまな意味になりえますが、本記事においては「Webページを構成するパーツ」と定義させていただきます。
目次
SMACSSを使う際に役立つテクニック編
まずはSMACSSを使う際に役立つテクニックからご紹介します。
Descendent Name
Descendent Nameは親のクラス名を受け継いでいくクラスの命名アイデアです。
実際に例を上げてみましょう。
<div class=“media“>
<img class=“media-image“ src=“...“ alt=“...“>
<div class=“media-body“>
<h2 class=“media-heading“>...</h2>
<div class=“media-text“>...</div>
</div>
</div>
上の例は「.media」というコンポーネントをマークアップした例です。
「.media」内の要素のクラス名が、全て親要素のクラス名「.media」を受け継いでいるのがわかるかと思います。
この命名ルールはBEMに少し似ています。
BEMはクラス名のバッティング回避、コンポーネントの再利用、コンポーネントのHTML構造の明瞭化などの点において優れています。
しかしその反面、ルールが厳格であったり、SMACSSなど他のアプローチと併用して使うのが難しかったりなど、導入の障壁が比較的高いです。
もしこのアプローチを使うのであれば、(BEMほど厳格で明瞭な書き方はできないものの)BEMの利点を生かしつつ比較的楽に導入にすることができます。
レイアウト調整用CSSの活用
コンポーネントをWebページに配置する際、レイアウト調整として汎用的に使えるCSSとクラスを用意しておくと、楽にWebページをつくることができます。
それは例えば以下のようなものです。
<ul class=“l-grid l-grid-col3“>
<li class=“l-grid-item“>
<img class=“thumbnail“ src=“...“ alt=“...“>
</li>
<li class=“l-grid-item“>
<img class=“thumbnail“ src=“...“ alt=“...“>
</li>
<li class=“l-grid-item“>
<img class=“thumbnail“ src=“...“ alt=“...“>
</li>
</ul>
.l-grid {
font-size: 0; /* inline-blockによる隙間を埋める */
}
.l-grid-item {
display: inline-block;
vertical-align: top;
font-size: 10px;
}
.l-grid-col2 > .l-list-item {
width: 50%;
}
.l-grid-col3 > .l-list-item {
width: 33.3333%;
}
.l-grid-col4 > .l-list-item {
width: 25%;
}
このように、レイアウト調整用CSSを使えば同じようなCSSを何度も書くことなく、再利用してコンポーネントを配置することができます。
レイアウト調整用CSSは自作してもいいですし、以下のようなCSSライブラリを使うことを検討してもよいでしょう。
-
Example: Stacked-to-horizontal|Bootstrap
http://getbootstrap.com/css/#grid-example-basic
BEMを使う際に役立つテクニック編
続いて、BEMを使う際に役立つテクニックです。
Mixes
Mixesは複雑なコンポーネントをマークアップする際に役立つテクニックです。
BEMの公式で紹介されている方法で、もしBEMやそれに準ずるマークアップを行っているのなら有効な手段でしょう。
ではどのようなシーンで利用できるのか。
<button class=“button“>Button</button>
.button {
display: inline-block;
color: #FFF;
background: #000;
text-decoration: none;
padding: 5px 20px;
border-radius: 3px;
font-size: 15px;
}
例えばよくあるシンプルなボタンがあったとします。
<!-- Before -->
<form class=“form“>
<table class=“form__table“>...</table>
<button class=“button“>利用規約に同意して送信する</button>
</form>
このボタンを、お問い合わせのフォーム内の一番下に「利用規約に同意して送信する」というテキストを内包した形で配置したいとします。
<!-- After -->
<form class=“form“>
<table class=“form__table“>...</table>
<button class=“form__button-small button“>利用規約に同意して送信する</button>
</form>
.form__button-small.button {
font-size: 13px;
}
しかしテキストが長すぎて見栄えが悪いため、このときのボタンのみフォントサイズを13pxに落としたい……という場合、Mixesによるマークアップが有効です。
.form .button {font-size: 13px;}
この他のスタイリングだと、上記のような書き方も考えられます。
ただしこの方法だと、もし「.form」内に複数の「.button」を配置することになった場合、意図しない「.button」にまで影響してしまいます。
また、Modifierクラスで対応することも検討できますが、あまり再利用する機会のない特異パターンの場合は不容易にModifierクラスを用意せず、Mixesで対応したほうが好ましいでしょう。
Wrap
Wrapもまた、複雑なコンポーネントをマークアップする際に役立つテクニックで、BEMとの相性がいいです。
いくつかの記事で紹介されていましたが、正式な呼び名がないため僕はWrapと呼んでいます。
ではWrapはどのようなシーンで利用できるのか。
例えば先ほどのボタンコンポーネントを、今度はヘッダーの中に右寄せで配置したいというとき、Wrapによるマークアップが有効です。
<header class=“site-header“>
<div class=“site-header__button-wrap“>
<button class=“button“>Button</button>
</div>
</header>
.site-header__button-wrap {
float: right;
}
この方法であれば、BEMのHTML構造を維持したままボタンを配置することができます。
Mixesを使ってもいいですが、Mixesの場合は「.button」コンポーネント自体にスタイルが追加されます。
あてるスタイルによってはコンポーネントの見た目に影響をおよぼしてしまうため、Wrapは今回の例のようにコンポーネント自体には影響を与えず、配置だけ操作したいといった場合に有効です。
margin調整用のModifierクラス
CSS設計を意識したコーディングを行っている場合、Modifierクラス(あるいはSkin、またはサブモジュールクラス)を利用する機会があるでしょう。
これらのクラスは主にコンポーネントの見た目を変え、バリエーション違いを作るために用いられます。
<button class=“button“>Button</button>
<button class=“button button--primary“>Button</button>
<button class=“button button--error“>Button</button>
.button {
display: inline-block;
text-decoration: none;
padding: 5px 20px;
border-radius: 3px;
font-size: 15px;
background: #000;
color: #fff;
}
.button--primary {
background: #27B018;
}
.button--error {
background: #F66A4E;
}
これ以外に、Modifierクラスはコンポーネント間のmarginを操作する目的で利用することができます。
例えば以下のようなHTMLがあった場合、セクションとセクションの間にはmarginが設けられていることでしょう。
そうした場合、Modifierクラスでmarginを設定する方法を使うと、こうなります。
<section class=“section section--layout-a“>
<h1>Section title</h1>
<p>...</p>
</section>
<section class=“section section--layout-b“>
<h1>Section title</h1>
<p>...</p>
</section>
<section class=“section section--layout-c“>
<h1>Section title</h1>
<p>...</p>
</section>
.section--layout-a {
margin-bottom: 32px;
}
.section--layout-b {
margin-bottom: 48px;
}
.section--layout-c {
margin-bottom: 64px;
}
marginの値がシンプルな値(10px,20pxなど)であれば、ヘルパークラス(あるいはユーティリティと呼ばれるCSS)を用いることが検討できますが、デザイン上そうもいかないことがあるでしょう。
また、複数のシーンで同じコンポーネントが再利用される場合はどこに置くかによってmarginの値が変わることも考えられますから、コンポーネント自体にmarginを設定することは避けたほうがいいといえます。
このような条件下(marginの値が細かく、かつコンポーネントを再利用することが前提の場合)では、Modifierによる指定が活用できます。
LIGはWebサイト制作を支援しています。ご興味のある方は事業ぺージをぜひご覧ください。