ガジェット通信

見たことのないものを見に行こう

【CSS設計】拡張や修正に強いコンポーネントをマークアップする6のテクニック

DATE:
  • ガジェット通信を≫

こんにちは! フロントエンドエンジニアのせいとです。
皆様、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
Kite
http://hiloki.github.io/kitecss/

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による指定が活用できます。

さまざまなシーンで役立つテクニック編

最後にさまざまなシーンで役立つテクニックをご紹介します。

略称との付き合い方

クラス名をつけるとき、名称が長いと単語を省略したくなりませんか?
しかしあまり無茶な略し方をすると、他の開発者に伝わらないことがあります。

たとえば、「.ttl」ーーこれが何の略か、わかりますか?
正解は「.title」の略です。以前僕がいた会社では皆が当たり前に使っていましたが、一般的ではなかったようでLIGでは伝わりませんでした。

ではそうすればいいのか。
解決策は3つあります。

1. 略語の原則禁止

僕がよく用いる方法は略語を禁止してしまうことです。
最もシンプルな方法です。

この方法は、名称が長くなるというデメリットがある代わりに、開発者個人が独自に名称を略して混乱を生むことを避けるメリットがあります。
また、クラス名が長くなることはクラス名のバッティングを下げ、コンポーネントの内容を推測する手助けすることにもつながるため、必ずしも悪いことばかりではないと僕は思っています。

しかしもし、プロジェクトメンバーに略語の禁止を反対された場合は、妥協案として「広く一般的に浸透している略称はOK」という例外を設けたりします。
広く一般的に、とは以下のようなものです。

large size → l-size
level → lv
navigation → navi

ただしこの「広く一般的に浸透しているかどうか」という基準は境界線が曖昧なため、あまり推奨はできません。

2. 略語辞典の利用

また、略語をドキュメント化してまとめた「略語辞典」を活用する方法もあります。
これはMCSSという方法論で推奨されているやり方です。

a
link (<a> tag)

ac
action

add
additional

aft
after

aux
auxillary

etc…

これを見ながらであれば、謎の略語に遭遇しても迷う心配はないでしょう。
ただ、略語辞典のドキュメントを見ながらコーディングを行うのは個人的にはわずらわしく感じるので、今現在僕は使っていません。

3. キャメルケースの採用

命名にチェインケースやスネークケースを用いている場合、単語の区切にハイフンやアンダーバーを使うことになるでしょう。
キャメルケースを採用すれば、単語の区切は大文字で表すため、一文字節約することができます。
わずかではありますが、クラス名を短くする手助けになります。

.media-heading → .mediaHeading

まとめ

いかがだったでしょうか。
美しいCSSを書く上で、本記事が皆さんの参考になれば幸いです。
今回記事を書くにあたって参考にさせていただいた文献と記事を以下に記しますので、興味がある方はぜひそちらも一読ください。

それでは、また!

参考文献&記事

SMACSS – Scalable and Modular Architecture for CSS
https://smacss.com/ja
BEM – Block, Element, Modifier
https://bem.info/
SUIT CSS documentation
https://github.com/suitcss/suit/blob/master/doc/README.md
MCSS – Multilayer CSS
http://operatino.github.io/MCSS/ja/
BEMによるフロントエンドの設計 | CodeGrid
https://app.codegrid.net/entry/bem-basic-1
Nesting Components | simurai.com
http://simurai.com/blog/2015/05/11/nesting-components/

カテゴリー : 生活・趣味 タグ :
LIGの記事一覧をみる ▶
  • 誤字を発見した方はこちらからご連絡ください。
  • ガジェット通信編集部への情報提供はこちらから
  • 記事内の筆者見解は明示のない限りガジェット通信を代表するものではありません。

TOP