読者です 読者をやめる 読者になる 読者になる

mixi engineer blog

ミクシィ・グループで、実際に開発に携わっているエンジニア達が執筆している公式ブログです。様々なサービスの開発や運用を行っていく際に得た技術情報から採用情報まで、有益な情報を幅広く取り扱っています。

なぜ @kotarok さんは mixin より extend を推すのか

CSS CSSプリプロセッサ LESS Sass

こんにちは。最近、実は JavaScript よりも Perl が好きなたんぽぽグループの大形です。 Perl の、仕様書など無いところがたまりません。勉強しても勉強しても...。いえ、今回は Perl の話ではありませんでした。

一昨日の土曜日ですが、会社にお金を出して貰って、 SwapSkills さんの『CSSを便利に使うための LESS入門』にお邪魔してきました。

何を隠そう、いや、隠すことは何も無いのですが、私は今「クライアントサイドのバックエンド担当」として働かせていただいてます。つまるところ、デザイナさんやコーダさんが日々目の前の案件と戦い続けている中で、一歩引いたところからお助けユーティリティを作ったり、俯瞰して工程を見直してみたり、デザインにおける継続テストの仕組みを考えたり、新しく何かの役に立ちそうなものをどこからか引っ張ってきたりするお仕事です。

そんなお仕事の一環として、今ミクシィでは CSS プリプロセッサの導入検証を行っています。その中でも、おそらく Sass です。 CSS プリプロセッサそのもののご説明は、最近日本語でもいろいろなところで読むことができますのでそちらに譲るとして、私が実証実験中に一番興味を持ったのが、 CSS プリプロセッサの日本の第一人者である @kotarok さん(小久保さん)が、 Sass が LESS より優れている点として、「 mixin に対する extend の優位性、使いやすさ、メンタルモデルのフィット感」を常に挙げていることでした。

そんな小久保さんが、こともあろうに LESS ( extend は公式にはまだありません)のイベントで CSS プリプロセッサについてお話しするとは一体何事であろうか。ということで、とても楽しみにしていたわけです。

有料のイベントですので、内容をここで事細かにお話しすることは憚られますが、小久保さんの「 CSS プリプロセッサ概論」では、現に長い期間既に CSS プリプロセッサを利用しておられ、かつキャンペーン、企業サイト、大規模ウェブアプリケーションといったほぼウェブの全てと言える広いフィールドで制作の経験がある方からの、スタイルルール記述の抽象性を高めることの意義と、 CSS プリプロセッサのさまざまなメリットを直接お伺いしてかなり胸に染みいりました。

また CSS Radar (もちろん私も CSS Radar Newsletter 購読してます!)の斉藤祐也さんによる「 LESS の機能紹介」は非常に刺激的でした。特に LESS は検証中にざっくり調べていた以上に機能が豊富で(もしや私が調べていたときからさらに追加になったものなのかも...)、また if といったプログラムライクな制御構文を極力 @media 等の CSS のネイティブな構文に寄せていこうとする LESS 開発者の努力には驚かされました。 LESS 、侮れません。

しかし、とにかく私が伺いたかったのは「 extend は mixin より何が優れているのか?」です。というわけで、質問コーナーで素早く挙手し、

「小久保さんにお伺いしたいのですが...」

と切り出したところ、

「今は斉藤さんへの質問の時間です」

と怒られてしまいました...。先走ってしまってすみませんでした...。斉藤さん、失礼いたしました...。

改めて、その後にもう一度お伺いしました。僕が思っていた以上に、小久保さんにはかなり気持ちの入った動機があって、ここで一言で纏められるものでは本来無いのですが、私はこのように理解し、納得しましたのでご紹介します。

元々 HTML/CSS の世界はまず DOM ありき HTML ドキュメントありきで、 CSS はその後に対象要素への経路であるセレクタを記述し、対象要素を彩るためのスタイルルールを適用していく、という流れであり、これには違和感があった。

この場合、同じようなスタイル、同じようなデザインにおける役割(つまりそれが CSS のスタイルルールセット)を、 CSS ファイル中に散逸したいろいろな複数の HTML 要素(つまりセレクタ)に対し複製していく感覚である。

このように、予め定義されたドキュメント要素に対しデザインロールを複製していくのでは無く、予め用意・設計したデザインロールに対し、「そのように振る舞わせたい」 HTML 要素を適用していく、この順番の方が小久保氏のプロセスイメージに近い。

HTML は XML とは異なり、汎用のツールである。ページ毎の最適化は、独自の要素を定義設計することで行うのでは無く、サイト毎に最適化したコンポーネントを定義設計した上で、そこに要素を「適用させる」ことである。 DOM をベースにしたセレクタ構造に対しアドホックなスタイルルールセットを適用すること、ではないのではないか(言われてみると、 XML と HTML の違いが CSS というスタイルルールセットに与える影響はかなり大きいですね)。

スタイルシートの考え方はウェブの前、 DTP や組版時代からあった(私は寡聞にしてこの辺りのことは存じ上げませんが...)。スタイルシートの考え方の源流はそこにあるはずだが、これがウェブ時代に入り、いろいろなチュートリアルの中でまずセレクタありきで紹介され続けた結果、文書とスタイルルールセットの関係が逆転してしまった。

スケーラブルな設計のためには、「要素からスタイル」ではなく、「コンポーネント定義から要素」であるべきではないか。スタイル、デザイン、役割が先にあり、それを文書のフラグメントに割り当てる方が最適なのでは無いか。

スタイルルール群が先にありきで「それをどこに当てるか?」を考えるのが本来の姿。その、「どこに当てるか」を増やしていくメンタルモデルに、 extend が近い。

いかがでしょうか。私は正直ここまで考えてもみなかったですが、具体的には次のような感じでしょうか。

mixin

@mixin ruleset {
  // あるスタイルルールセット、つまり、ある表現上の役割
}
 
.selector {
  // ある役割を、セレクタ( HTML 要素)に対し当てはめる。
  @include ruleset;
}
 
.selector2 {
  // 他の要素に対して同じ役割を与える。
  @include ruleset;
}
 
// これは結果として
 
.selector {
  // ルールセット
}
 
.selector2 {
  // ルールセット
}
 
// このように「セレクタに対しルールセットを複製する」イメージとなる。

extend

.selector {
  // この内容が、あるルールセット
}
 
.selector2 {
  @extend .selector;
}
 
.selector3 {
  @extend .selector;
}
 
// これは結果として
 
.selector, .selector2, .selector3 {
  // あるスタイルルールセット
}
 
// このように「ルールセットに対しセレクタを積み上げる」イメージとなる。

具体的に記述してみると、これは顕著に違います。

// Sass
 
/* mixin */
@mixin role {
  font-size:15px;
}
 
.selector1 {
  @include role;
}
 
.selector2 {
  @include role;
}
 
.selector3 {
  @include role;
}
 
/* extend */
.selector4 {
  color:#f00;
}
 
.selector5 {
  @extend .selector4;
}
 
.selector6 {
  @extend .selector4;
}
 
.selector7 {
  @extend .selector4;
}
/* CSS */
 
/* mixin */
.selector1 {
  font-size: 15px; }
 
.selector2 {
  font-size: 15px; }
 
.selector3 {
  font-size: 15px; }
 
/* extend */
.selector4, .selector5,
.selector6, .selector7 {
  color: #f00; }

いかがでしょうか。この件については、さきほど社内のデザイナとも議論をしました。表現中の役割が先か、文書が先か。スタイルを役割というところまで拡大解釈できるのか。役割を定義するのは CSS なのか、 HTML なのか、 JavaScript なのか。どのようなページ、どのようなアプリケーションにおいてスタイルファーストが最適なのか。

何ら結論のある話ではありませんが、弊社のクライアントサイドチームは特に「ウェブアプリケーション」を専らに制作しておりますので、 Web Components 的な方向性を見やりつつ、まずは CSS プリプロセッサで楽したい!。そのように思う次第です。

そこ!。 mixin のロジックがもっと CSS を最適化してくれて、 extend と同じような出力になったらそれでいいんじゃないの?。とか言わないように!。今回は情熱のお話です。