@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;
}
プレイグラウンド

Sass構文

.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;
}
プレイグラウンド

Sass構文

.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の定義を明確で分かりやすく保ち、実装をクリーンで効率的にするために、この動作は非推奨となり、将来のバージョンから削除されます。

詳細については、破壊的変更ページを参照してください。

拡張できるのは、.infoaのような個々のセレクターである単純セレクターのみです。.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