@extend
ページのデザインにおいて、あるクラスが別のクラスのすべてのスタイルと独自の特定のスタイルを持つべきである場合がよくあります。たとえば、BEMメソッドは、ブロックまたは要素クラスと同じ要素にある修飾子クラスを推奨しています。しかし、これはHTMLを乱雑にする可能性があり、両方のクラスを含めるのを忘れることでエラーが発生しやすく、非セマンティックなスタイルに関する問題をマークアップに持ち込む可能性があります。
<div class="error error--serious">
Oh no! You've been hacked!
</div>
.error {
border: 1px #f00;
background-color: #fdd;
}
.error--serious {
border-width: 3px;
}
Sassの@extend
ルールはこれを解決します。@extend <selector>
と書かれ、Sassに、あるセレクタが別のセレクタのスタイルを継承することを指示します。
SCSS構文
.error {
border: 1px #f00;
background-color: #fdd;
&--serious {
@extend .error;
border-width: 3px;
}
}
Sass構文
.error
border: 1px #f00
background-color: #fdd
&--serious
@extend .error
border-width: 3px
CSS出力
.error, .error--serious {
border: 1px #f00;
background-color: #fdd;
}
.error--serious {
border-width: 3px;
}
あるクラスが別のクラスを拡張する場合、Sassは、拡張するクラスと一致するすべての要素を、拡張されるクラスとも一致するようにスタイル設定します。あるクラスセレクタが別のクラスセレクタを拡張する場合、それは、既に拡張するクラスを持つHTMLのすべての要素に拡張されたクラスを追加したのとまったく同じように機能します。class="error--serious"
と書くだけで、Sassはそれがclass="error"
も持っているかのようにスタイル設定します。
もちろん、セレクタはスタイルルールで単独で使用されるだけではありません。Sassは、セレクタが使用されている場所すべてを拡張します。これにより、要素は拡張されたセレクタと一致した場合とまったく同じようにスタイル設定されます。
SCSS構文
.error:hover {
background-color: #fee;
}
.error--serious {
@extend .error;
border-width: 3px;
}
CSS出力
.error:hover, .error--serious:hover {
background-color: #fee;
}
.error--serious {
border-width: 3px;
}
⚠️ 注意!
拡張は、スタイルシートの残りの部分がコンパイルされた後に行われます。親セレクタが解決された後に行われます。つまり、@extend .error
の場合、.error { &__icon { ... } }
の内部セレクタには影響しません。SassScriptの親セレクタは、extendの結果を参照できません。
動作方法動作方法 permalink
ミックスインはスタイルを現在のスタイルルールにコピーしますが、@extend
は、拡張されたセレクタを含むスタイルルールを更新して、拡張するセレクタも含めるようにします。セレクタを拡張する場合、Sassはインテリジェントな統合を行います。
-
決して、
#main#footer
のような、いかなる要素にも一致しないセレクタは生成しません。 -
HTML要素がどのようにネストされていても機能するように、複雑なセレクタがインターリーブされるようにします。
-
冗長なセレクタを可能な限り削除しながら、特異性が拡張子以上であることを保証します。
-
あるセレクタが別のセレクタのすべてに一致する場合を認識し、それらを組み合わせることができます。
-
コンバイナ、ユニバーサルセレクタ、およびセレクタを含む擬似クラスをインテリジェントに処理します。
SCSS構文
.content nav.sidebar {
@extend .info;
}
// This won't be extended, because `p` is incompatible with `nav`.
p.info {
background-color: #dee9fc;
}
// There's no way to know whether `<div class="guide">` will be inside or
// outside `<div class="content">`, so Sass generates both to be safe.
.guide .info {
border: 1px solid rgba(#000, 0.8);
border-radius: 2px;
}
// Sass knows that every element matching "main.content" also matches ".content"
// and avoids generating unnecessary interleaved selectors.
main.content .info {
font-size: 0.8em;
}
Sass構文
.content nav.sidebar
@extend .info
// This won't be extended, because `p` is incompatible with `nav`.
p.info
background-color: #dee9fc
// There's no way to know whether `<div class="guide">` will be inside or
// outside `<div class="content">`, so Sass generates both to be safe.
.guide .info
border: 1px solid rgba(#000, 0.8)
border-radius: 2px
// Sass knows that every element matching "main.content" also matches ".content"
// and avoids generating unnecessary interleaved selectors.
main.content .info
font-size: 0.8em
CSS出力
p.info {
background-color: #dee9fc;
}
.guide .info, .guide .content nav.sidebar, .content .guide nav.sidebar {
border: 1px solid rgba(0, 0, 0, 0.8);
border-radius: 2px;
}
main.content .info, main.content nav.sidebar {
font-size: 0.8em;
}
💡豆知識
セレクタ関数を使用して、Sassのインテリジェントな統合に直接アクセスできます!selector.unify()
関数は、2つのセレクタの交点に一致するセレクタを返し、selector.extend()
関数は@extend
と同様に機能しますが、単一のセレクタに対して機能します。
⚠️ 注意!
@extend
は拡張されたセレクタを含むスタイルルールを更新するため、それらのスタイルは、@extend
の出現場所ではなく、拡張されたセレクタのスタイルルールの出現場所に基づいて、カスケードでの優先順位を持ちます。これは混乱を招く可能性がありますが、覚えておいてください。これは、拡張されたクラスをHTMLに追加した場合と同じ優先順位です。
プレースホルダーセレクタプレースホルダーセレクタ permalink
拡張のみを目的とするスタイルルールを書きたい場合があります。その場合、プレースホルダーセレクタを使用できます。これは、.
ではなく%
で始まるクラスセレクタのように見えます。プレースホルダーを含むセレクタはCSS出力には含まれませんが、それらを拡張するセレクタは含まれます。
SCSS構文
.alert:hover, %strong-alert {
font-weight: bold;
}
%strong-alert:hover {
color: red;
}
CSS出力
.alert:hover {
font-weight: bold;
}
プライベートプレースホルダープライベートプレースホルダー permalink
モジュールメンバーと同様に、プレースホルダーセレクタは、名前を-
または_
で始めることでプライベートとしてマークできます。プライベートプレースホルダーセレクタは、それを定義するスタイルシート内でのみ拡張できます。他のスタイルシートでは、そのセレクタが存在しないように見えます。
拡張スコープ拡張スコープ permalink
あるスタイルシートがセレクタを拡張する場合、その拡張は、上流のモジュール(つまり、@use
ルールまたは@forward
ルールを使用してそのスタイルシートによってロードされるモジュール、それらのモジュールによってロードされるモジュールなど)で記述されたスタイルルールにのみ影響します。これにより、@extend
ルールをより予測しやすくし、記述時に認識していたスタイルのみに影響するようにします。
⚠️ 注意!
@import
ルールを使用している場合は、拡張はまったくスコープされません。インポートするすべてのスタイルシートに影響を与えるだけでなく、あなたのスタイルシートをインポートするすべてのスタイルシート、それらのスタイルシートがインポートするその他すべて、などに影響を与えます。@use
がない場合、拡張はグローバルです。
必須とオプションの拡張必須とオプションの拡張 permalink
通常、@extend
がスタイルシートのセレクタと一致しない場合、Sassはエラーを生成します。これは、タイポを防いだり、セレクタの名前を変更しても、そこから継承するセレクタの名前を変更せずに済むようにするためです。拡張されたセレクタが存在することを要求する拡張は、必須です。
ただし、常にこれが必要なわけではありません。拡張されたセレクタが存在しない場合に@extend
が何も実行しないようにするには、末尾に!optional
を追加します。
拡張またはミックスイン?拡張またはミックスイン? permalink
拡張とミックスインはどちらもSassでスタイルをカプセル化して再利用する方法であり、どちらを使用するかという疑問が自然に生じます。引数を使用してスタイルを構成する必要がある場合は、ミックスインが明らかに必要ですが、単なるスタイルの塊の場合はどうでしょうか?
経験則として、セマンティッククラス(またはその他のセマンティックセレクタ)間の関係を表す場合は、拡張が最適な選択肢です。.error--serious
クラスを持つ要素はエラーであるため、.error
を拡張するのが理にかなっています。しかし、非セマンティックなスタイルのコレクションの場合は、ミックスインを作成することでカスケードの問題を回避し、後から簡単に構成できるようにすることができます。
💡豆知識
ほとんどのWebサーバーは、同一のテキストの繰り返しを処理することに非常に優れているアルゴリズムを使用して、提供するCSSを圧縮します。つまり、ミックスインは拡張よりも多くのCSSを生成する可能性がありますが、ユーザーがダウンロードする必要がある量を大幅に増加させることはおそらくありません。そのため、最も少ないCSSを生成するものだけでなく、ユースケースに最も適した機能を選択してください。
制限事項制限事項パーマリンク
許可されていないセレクター許可されていないセレクターパーマリンク
- Dart Sass
- ✓
- LibSass
- ✗
- Ruby Sass
- ✗
LibSassとRuby Sassは現在、.message.info
のような複合セレクターの拡張を許可しています。しかし、この動作は@extend
の定義と一致しません。拡張セレクターに一致する要素をclass="message info"
のようにスタイル設定する代わりに(.message
または.info
のいずれかを含むスタイルルールに影響を受ける)、.message
と.info
の両方を含むルールでのみスタイル設定されます。
@extend
の定義を明確で分かりやすく保ち、実装をクリーンで効率的にするために、この動作は非推奨となり、将来のバージョンから削除されます。
詳細については、破壊的変更ページを参照してください。
拡張できるのは、.info
やa
のような個々のセレクターである単純セレクターのみです。.message.info
を拡張できるとしたら、@extend
の定義によれば、エクステンダに一致する要素は.message.info
に一致するようにスタイル設定されます。これは.message
と.info
の両方に一致することと同じなので、@extend .message, .info
の代わりに記述することには利点がありません。
同様に、.main .info
を拡張できるとしたら、それは(ほぼ).info
単独で拡張することと同じになります。微妙な違いは、本質的に異なることをしているように見える混乱に見合う価値はありません。そのため、これも許可されていません。
SCSS構文
.alert {
@extend .message.info;
// ^^^^^^^^^^^^^
// Error: Write @extend .message, .info instead.
@extend .main .info;
// ^^^^^^^^^^^
// Error: write @extend .info instead.
}
Sass構文
.alert
@extend .message.info
// ^^^^^^^^^^^^^
// Error: Write @extend .message, .info instead.
@extend .main .info
// ^^^^^^^^^^^
// Error: write @extend .info instead.
HTMLヒューリスティックHTMLヒューリスティックパーマリンク
@extend
が複雑なセレクターをインターリーブする際、すべての祖先セレクターの可能な組み合わせを生成しません。生成できるセレクターの多くは、実際のHTMLに実際に一致する可能性が低く、すべてを生成するとスタイルシートが大きくなりすぎて、実質的な価値はほとんどありません。代わりに、ヒューリスティックを使用します。各セレクターの祖先は、他のセレクターの祖先とインターリーブされることなく、自己完結型であると仮定します。
SCSS構文
header .warning li {
font-weight: bold;
}
aside .notice dd {
// Sass doesn't generate CSS to match the <dd> in
//
// <header>
// <aside>
// <div class="warning">
// <div class="notice">
// <dd>...</dd>
// </div>
// </div>
// </aside>
// </header>
//
// because matching all elements like that would require us to generate nine
// new selectors instead of just two.
@extend li;
}
Sass構文
header .warning li
font-weight: bold
aside .notice dd
// Sass doesn't generate CSS to match the <dd> in
//
// <header>
// <aside>
// <div class="warning">
// <div class="notice">
// <dd>...</dd>
// </div>
// </div>
// </aside>
// </header>
//
// because matching all elements like that would require us to generate nine
// new selectors instead of just two.
@extend li
CSS出力
header .warning li, header .warning aside .notice dd, aside .notice header .warning dd {
font-weight: bold;
}
@media内の拡張@media内の拡張パーマリンク
@extend
は@media
およびその他のCSS atルール内で許可されていますが、そのatルール外に出現するセレクターを拡張することは許可されていません。これは、拡張セレクターが指定されたメディアコンテキスト内でのみ適用され、スタイルルール全体を複製せずに、その制限が生成されたセレクターに確実に保持される方法がないためです。
SCSS構文
@media screen and (max-width: 600px) {
.error--serious {
@extend .error;
// ^^^^^^
// Error: ".error" was extended in @media, but used outside it.
}
}
.error {
border: 1px #f00;
background-color: #fdd;
}
Sass構文
@media screen and (max-width: 600px)
.error--serious
@extend .error
// ^^^^^^
// Error: ".error" was extended in @media, but used outside it.
.error
border: 1px #f00
background-color: #fdd