CSSの汎用クラスのつかいどころ
2014-01-13
OOCSSをはじめとするCSS設計におけるモジュール指向のアプローチの話になると、下記のような単一プロパティで定義されたルールを組み合わせたものを指す、というような説明がされる場合がある。
.size1of4 {
width: 25%;
}
.mrs {
margin-right: 10px;
}
.font-small {
font-size: 10px;
}
.text-left {
text-align: left;
}
これらはUtilityとか、Helperとか、汎用クラスというように呼ばれ、あれば何かと便利なルールだ。
どういうときに便利かというのは、唐突なデザイン変更要求などに、都度そのためのルールを定義するよりも、これらの汎用クラスの組み合わせで対応できるということが挙げられるだろう。
<div class="mts text-center">
<img src="banner.png" alt="キャンペーンバナー">
</div>
これが本当に一時的に使われるものであれば許容範囲ではあると思うが、すべてのモジュールがこのように構築されていくと、混沌としたコードになることがある。
.mr10 {
margin-right: 10px;
}
.mr11 {
margin-right: 11px;
}
.mr13 {
margin-right: 13px;
}
.mr15 {
margin-right: 15px;
}
/* etc,etc... */
対象のサイト、アプリケーションが数百、数千もの’margin-right: 10px;‘を宣言しているような規模であれば、これをひとつのモジュールとしてしまうような方法はありかもしれない。が、多くのサイトはそんなことはない。いずれにせよ、1px刻みでルールが増えるような状態は健全ではないので、それはデザイナーと殴りあう話しあう方が良いとは思う。
で、ここからが本題。
次のようなMediaオブジェクトがある。これをひとつのモジュールとして定義したい。
<div class="media">
<img src="http://placesheen.com/88/88" class="media__image" />
<div class="media__body">Charlie Sheen</div>
</div>
.media__image {
display: block;
float: left;
margin-right: 20px;
}
注目してほしいところは、写真と本文の間のマージンであるmargin-right: 20px;
の部分。
この部分を先ほどの汎用クラスとして置き換えるならこうなる。
<div class="media">
<img src="http://placesheen.com/88/88" class="media__image mrm" />
<div class="media__body">Charlie Sheen</div>
</div>
.media__image {
display: block;
float: left;
}
.mrm { // Margin Right Medium
margin-right: 20px;
}
このようにすれば、マージンが状況に応じて狭くしたいときも、.mrs
などに置き換えればmargin-right: 10px;
のようにすることができるだろう。
これはこれで、そのように意図的に設計されているのであれば良いが、個人的には好ましいとは思わない。
なぜならオブジェクト/モジュールとしてそのルールを含めておくべきだと考えているからだ。
では上記のように値を変える必要があるならばどのようにするか。
<div class="media">
<img src="http://placesheen.com/88/88" class="media__image media__image--small" />
<div class="media__body">Charlie Sheen</div>
</div>
.media__image {
display: block;
float: left;
margin-right: 20px;
}
.media__image--small { // Modifier
margin-right: 10px;
}
.media__image
のモディファイア(修飾パターン)として、.media__image--small
で定義する、というアプローチだ。
またはオブジェクト全体として小さめのサイズのものをつくるというならば、次のようなパターンもある。
<div class="media media--small">
<img src="http://placesheen.com/88/88" class="media__image" />
<div class="media__body">Charlie Sheen</div>
</div>
.media--small media__image {
margin-right: 10px;
}
この場合は.media
のモディファイアとして、.media--small
を定義し、その子である.media__image
をスタイルを調整している。
これがもちろんすべてのケースに置いて正しいとはいえないのだが、モジュール設計においては、単純にルールを再利用したいという理由だけで汎用クラスをその中に組み込むべきではない、と考えている。
一方で汎用クラスが使えるケースもある。それは異なるモジュール間でのレイアウトのために使われるような時だ。
<div class="photo mbs">...</div>
<div class="media mbm">...</div>
<div class="comment">...</div>
これも設計や実装によりけりだが、モジュール間のレイアウト関係に関するルールは、そのモジュール自体には持たせない方が良いこともある。つまりは次のように、.media
モジュールに対し、margin-bottom: 10px
といった値を持たせるべきではない、ということだ。
.media {
/* Some rules */
margin-bottom: 10px;
}
このようにすべき、という兆しは、次のようなルールがいたるところで見えてきたときだ。
<div class="media mb0">...</div>
.media {
/* Some rules */
margin-bottom: 10px;
}
.mb0 {
margin-bottom: 0;
}
これは.media
にmargin-bottom
を持たせるべきではなかった、というのが明らかになっている。
まとめ
こういう話をするたびに付け加えるのは、これがすべてのケースにおいて正しいわけではないということ。こういうことを一応書いておかないと、どこかのBEMのように変なひとり歩きをすることがあるので。
あと加えて汎用クラスを使ったきゅうきょくのしーえしゅえしゅもあるが、これはこれで非常に面白い。 このフレームワークが誕生した経緯と、その成果を目にしているものとしては素晴らしいアプローチと評価する反面、下手にこのアプローチを採用することは、本記事でも書いたとおり、混沌しか生み出さないこともあるので気をつけよう。