Sass の @extend はどこがすごいのか

この記事では 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 関連で参考になった記事をいくつかリストアップしておきます:

えー、タイトルで「どこがすごいのか」と大見得を切っておきながらこれといった結論に至らずお恥ずかしい限りです。あと、アドベントカレンダーのスケジュールを乱してまことに申し訳ございませんでした!