Sassの勉強 #06 スタイルの継承ができる「@extend」
@extend 基本
「@extend」は指定したセレクタのスタイルを継承できる機能。ルールセットの中で中で他のセレクタで指定してあるルールをそのまま流用できます。
@extend セレクタ;
書き方はこれでOK。簡単。シンプルな例で見てみると、こんな感じになります。
// .test01のルールセットを.test02へ継承 .test01{ width:100%; background:#f1f1f1; } .test02{ @extend .test01; } /* コンパイル後 */ .test01, .test02 { width: 100%; background: #f1f1f1; }
コンパイル後は継承元と継承した先のセレクタがグループ化されます。
ほぼ同じスタイルを使いまわしたいけど、1つだけプロパティの値を変更したいなんて場合も簡単です。
.test01{ width:100%; background:#f1f1f1; } .test02{ @extend .test01; width:90%; } /* コンパイル後 */ .test01, .test02 { width: 100%; background: #f1f1f1; } .test02 { width: 90%; }
共通するプロパティはグループ化され、差分箇所だけが新しいルールセットに収まります。逆に言えばグループ化したくない場合は@extendは使わない方がいいのかも。
@extendが使えるセレクタ
- タイプセレクタ / div、p、strong・・・
- IDセレクタ / #id・・・
- クラスセレクタ / .class・・・
- 連結セレクタ / #id.class・・・
- 擬似クラス / :hover、:first-child・・・
- 擬似要素 / :before、:after・・・
- 属性セレクタ / input[type="text"]、a[href$=".pdf"]・・・
@extendが使えないセレクタ
- 子孫セレクタ(E F) / p strong、#main p・・・
- 子セレクタ(E > F) / .sample > p、p > strong・・・
- 隣接(E + F )セレクタ / h1 + h2、h3 + p・・・
- 間接セレクタ(E ~ F ) / h3 ~ h3、li ~ li・・・
使えないセレクタを継承しようとするとエラーが出る。
なんていうか…複雑なセレクタは@extendは無理って覚える!
但し、ネストされたセレクタ自体に@extendを使うことはできるとのこと。リファレンスの例ではこういうこと。
#fake-links .link { @extend a; } a { color: blue; &:hover { text-decoration: underline; } } /* コンパイル後 */ a, #fake-links .link { color: blue; } a:hover, #fake-links .link:hover { text-decoration: underline; }
便利な使い方 「@extend」専用のSassファイルを使う
「@extend」の基本は上述の通り。これをどう便利に使うか。教科書の説明が分かりやすすぎたので公式サポートサイトからソースをまた拝借して(一部カットしてシンプルにしています)…まずパーシャルを利用して「_extend.scss」というファイルを作る。
// _extend.scss .btnBase { text-align: center; margin: 0 0 10px; a { display: block; padding: 10px 20px; background: #999; color: #fff; &:hover { background: #ccc; color: #333; } } }
それをメインのscssファイルにインポートして使う。
// main.scss @import "extend"; ul.btnList { li { @extend .btnBase; } } .item { width: 300px; .text { overflow: hidden; .btn { @extend .btnBase; text-align: left; } } }
するとCSSファイルにはこう出力される。
// main.css .btnBase, ul.btnList li, .item .text .btn { text-align: center; margin: 0 0 10px; } .btnBase a, ul.btnList li a, .item .text .btn a { display: block; padding: 10px 20px; background: #999; color: #fff; } .btnBase a:hover, ul.btnList li a:hover, .item .text .btn a:hover { background: #ccc; color: #333; } .item { width: 300px; } .item .text { overflow: hidden; } .item .text .btn { text-align: left; }
上の例はボタン的なスタイルを当てる内容なのだけれども、こんな感じでベースとなるスタイルを使いまわしして使う箇所毎に少しだけ内容を変更したい際に便利、と。
@extend専用ファイル内のセレクタを最終的なCSSには反映したくないわって場合は後述のプレースホルダーセレクタ「%」を利用すればOK。
@extend専用 プレースホルダーセレクタ「%」
プレースホルダーセレクタ「%」は、@extend利用時にのみ使える特別なセレクタで、コンパイル後にはソースが残らない。
プレースホルダーセレクタを使ってscssファイルにルールを書いておいて@extendで使いまわしして、最終的には無駄なソースは残さずにcssファイルが仕上がる、という仕組み。
同一ルールセット内で複数継承する
@extendは同じルールセット内で複数指定する事も可能。
.test01{ color:red; font-size:1.1em; } .test02{ border:3px solid #ccc; } .sample{ @extend .test01; @extend .test02; width:90%; margin:0 auto 30px; } /* コンパイル後 */ .test01, .sample { color: red; font-size: 1.1em; } .test02, .sample { border: 3px solid #ccc; } .sample { width: 90%; margin: 0 auto 30px; }
複数する場合も使い方は一緒。@extendの後に呼び出したいセレクタを指定。
継承する数が増えてプロパティがバッティングした際は、CSSの個別性の計算通りに後から書かれたスタイルが優先される。
@extendの連鎖
すごくシンプルな例ですが、下記は「.chain01」の中身を「.chain02」内へ継承、更に「.chain02」を「.chain03」内へ継承しています。
.chain01{ color:red; } .chain02{ @extend .chain01; //.chain01を継承 font-weight:bold; } .chain03{ @extend .chain02; //.chain02を継承 margin:10px auto; }
これをコンパイルすると出力されるCSSソースは以下の通り。
/* コンパイル後 */ .chain01, .chain02, .chain03 { color: red; } .chain02, .chain03 { font-weight: bold; } .chain03 { margin: 10px auto; }
「.chain03」で「(.chain01を継承している).chain02」を継承しているので、「.chain01」の中身も「.chain03」へ継承されます。文章で説明するの難しいなコレ。
まぁ要は@extendで継承したルールは継承したセレクタをまた継承することで連鎖していく、と。
この連鎖は便利な面もあるけれども、複雑な内容になればなるほど、本来必要のない無駄な継承が増えていく、それをまた上書きしていく必要が出てくる…なんて場合もあるかもなので、ちょっと注意が必要かなとも思いました。
@mediaの内側では外側に書かれているセレクタは継承できない
@extendは@mediaの外で使われているセレクタは継承出来ない。@mediaの中から他のセレクタは@extendで呼び出そうとするとエラーが出ます。
解決方法は、@mediaのルールセットの中に継承したいセレクタを書けば良いとのこと。
逆に@mediaの中に書いたセレクタは@mediaの外からでもエラーなしで継承できます。ががが、コンパイル後は@mediaの中にグループ化されて展開されるのでまたまた困る。ということで…
@mediaの内側の継承と、@mediaの外側の継承は分けて考える!←覚える。
「!optional」フラグ
@extendで存在しないセレクタを継承しようとするとエラーが出ます。それを回避するのが、「!optional」フラグ。
書き方は「!important」のようにプロパティの値の後に書く。
#test{ @extend .dummy !optional; }
こんな感じ。そうすると、エラーは出なくなる。同時にその継承させようとした部分は出力されない。
Sassの勉強 関連記事
- Sassの勉強 #00 もっかい最初からやり直そうSassの巻
- Sassの勉強 #01 Sassとは何か?~環境構築
- Sassの勉強 #02 Sassの基本的な機能「ネスト」
- Sassの勉強 #03 Sassの基本的な機能「変数」
- Sassの勉強 #04 Sassの基本的な機能「演算」
- Sassの勉強 #05 Sassの基本的な機能「@import」
- Sassの勉強 #06 スタイルの継承ができる「@extend」
- Sassの勉強 #07 柔軟なスタイル定義が出来る「@mixin」
- Sassの勉強 #08 制御構文(条件分岐・繰り返し)
- Sassの勉強 #09 @at-root
- Sassの勉強 #10 Sassの勉強 #10 関数一覧(Ver.3.4) と自作関数