この記事では Less & Sass Advent calendar 2011 の 16 日目として、Sass の @extend
機能について書いてみます。が、諸事情により締め切りを過ぎてからあわてて書いており、かなりとっ散らかったものになるであろうことをあらかじめお断りしておきます。
さて、まずは @extend
の基本的な機能についてざっとおさらい。@extend
される側として一連のスタイルを定義したセレクタがあり、そのセレクタを @extend
で継承しつつプロパティを追加したりして、新しいセレクタを作ります:
// SCSS
// 継承元のセレクタ
.button {
display: inline-block;
border: 1px solid gray;
background-color: silver;
&:hover {
border-color: black;
}
}
// .button セレクタを継承・拡張
.button-download {
@extend .button; // .button を継承
background-color: green; // プロパティを上書き
border-radius: 4px; // 新たなプロパティの追加
.icon { // ネストしたセレクタの追加
background: url(/img/download.png) no-repeat 0 50%;
}
}
この SCSS をコンパイルすると、こういう CSS が生成されます:
/* CSS */
.button,
.button-download {
display: inline-block;
border: 1px solid gray;
background-color: silver;
}
.button:hover,
.button-download:hover {
border-color: black;
}
.button-download {
background-color: green;
border-radius: 4px;
}
.button-download .icon {
background: url(/img/download.png) no-repeat 0 50%;
}
このように、共通するプロパティはひとつのルールセットに、そして差分だけが新たなルールセットにまとめられ、じつに合理的なコードが生成されます。ここでは 2 つのセレクタ間でしか @extend
していませんが、これが増えてくるとさらにありがたみが増します。ボタンを例に出しましたが、たとえばリストやテーブルなど、基本的には似てるんだけど少しずつ違うスタイルのモジュールがいくつもある、みたいなときに威力を発揮します。
しかし、これだったら ミックスイン でもいいんじゃないの、という意見もあるかもしれません。この場合で言うと、.button
のスタイルをミックスイン化して .button-download
のルールセット内で @include
すれば、結果として同じスタイルを実現することはできます。しかし、そこに至る考え方が @extend
とミックスインではまるで違うのです。
ミックスインは、@include
で挿入した箇所で展開されるコード片です。ミックスイン自体のコードは CSS としてコンパイルされず、@include
されてはじめて実体を持ちます。そのため、使いそうなものをひととおりライブラリとして読み込んでおいて必要に応じて呼び出す、という使い方が可能です。
一方 @extend
は、実際に存在している CSS のスタイルをもとにしたものです。一連のスタイル定義をいわば「スタイルオブジェクト」として捉え、@extend
によってそれを継承・拡張して新たなオブジェクトを作るもの、と考えられます。
この「スタイルオブジェクト」というのは僕が勝手に呼んでいる名前で、なんとなくぼんやりとそう捉えている、というものです。僕はプログラマでもなければオブジェクト指向をきっちり勉強した経験もないので (こないだ友人の @marugoshi さんにちょっとだけご教授いただきましたが)、ここでぜひ皆さんのご意見をうかがいたいんですが、これってひょっとしてオブジェクト指向ですか?
上の SCSS のコードでやってることって、.button
っていうひとつのオブジェクトがあって、それを継承しつつも一部のプロパティが違ったり新たなプロパティが追加された .button-download
っていうもうひとつのオブジェクトが生成されてる、っていうふうに捉えてるんですが…
そして僕はこういうふうにスタイルを捉えるようになって、明らかにマークアップとスタイルの設計が変わったんですよ。それまで、CSS ってどう書いても最終的にはグチャグチャになる運命 (さだめ) なのでは… と思っていたんですが、はじめてスタイルというものが実体を持って見えるようになった、ような気がしたんです、Sass の @extend
を使うようになって。
オブジェクト指向の CSS というと OOCSS というのが有名ですけど、あれってどうも曲解されているというか、ようするにスタイルをクラスに細切れにしてマークアップにぽんぽん放り込めばいいんでしょ、みたいな見方をされてる気がするんですよ。たとえばこんなの:
<a class="button button-download button-rounded button-green text-bold align-center valign-top font-15">ダウンロード</a>
これはさすがに極端ですが、でもいわゆる CSS フレームワーク的なアプローチを採ろうとすると多かれ少なかれこういったマークアップになりがちな気がします。
そうではなくて、マークアップをシンプルに保ち、かつスタイルを変更する際になるべく影響を受けないよいうに、あらかじめマークアップの各要素というかモジュールごとにスタイルとは切り離した適切な名前をつけておいて、スタイルはスタイルでオブジェクトとして体系化してマークアップから分離する、みたいな理想にオブジェクト指向な Sass で少し近づけるのかも… とか考えるんですが、どうでしょう。
最後に、Sass の @extend
関連で参考になった記事をいくつかリストアップしておきます:
- Selector Inheritance the Easy Way: Introducing @extend : Nex3: 開発者のブログ
- Sassの@extendでCSSとHTMLをシンプルに - あと味: 入門編として簡潔にまとまっていてわかりやすい
- Sass(Scss) Memo: @extend | Culture27:
じつはややこしい
@extend
の仕様がかなり詳細に調べられていて素晴らしいです - Extends and Control Directives: Two Crazy Things Sass Can Do That LESS Can’t | Design Shack:
Sass は LESS と違って
@extend
とか使えてヤバい、という話 (あわせて読みたい: LESSにextendを実装してみた - hokaccha.hamalog v2) - The problem with CSS pre-processors | Blog | Miller Medeiros:
Sass の問題点や要望など。
@extend
の継承元をコンパイルされないようにする機能とかたしかにあるといかも
えー、タイトルで「どこがすごいのか」と大見得を切っておきながらこれといった結論に至らずお恥ずかしい限りです。あと、アドベントカレンダーのスケジュールを乱してまことに申し訳ございませんでした!