` will be inside or
// outside `
`, 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
<% end %>
<% fun_fact do %>
You can directly access Sass's intelligent unification using [selector
functions][]! The [`selector-unify()` function][] returns a selector that
matches the intersection of two selectors, while the [`selector-extend()`
function][] works just like `@extend`, but on a single selector.
[selector functions]: ../modules/selector
[`selector-unify()` function]: ../modules/selector#selector-unify
[`selector-extend()` function]: ../modules/selector#selector-extend
<% end %>
<% heads_up do %>
Because `@extend` updates style rules that contain the extended selector, their
styles have precedence in [the cascade][] based on where the extended selector's
style rules appear, *not* based on where the `@extend` appears. This can be
confusing, but just remember: this is the same precedence those rules would have
if you added the extended class to your HTML!
[the cascade]: https://developer.mozilla.org/en-US/docs/Web/CSS/Cascade
<% end %>
## Placeholder Selectors
Sometimes you want to write a style rule that's *only* intended to be extended.
In that case, you can use [placeholder selectors][], which look like class
selectors that start with `%` instead of `.`. Any selectors that include
placeholders aren't included in the CSS output, but selectors that extend them
are.
[placeholder selectors]: ../style-rules/placeholder-selectors
<%= partial "code-snippets/example-placeholder" %>
## Mandatory and Optional Extends
Normally, if an `@extend` doesn't match any selectors in the stylesheet, Sass
will produce an error. This helps protect from typos or from renaming a selector
without renaming the selectors that inherit from it. Extends that require that
the extended selector exists are *mandatory*.
This may not always be what you want, though. If you want the `@extend` to do
nothing if the extended selector doesn't exist, just add `!optional` to the end.
## Extends or Mixins?
Extends and [mixins][] are both ways of encapsulating and re-using styles in
Sass, which naturally raises the question of when to use which one. Mixins are
obviously necessary when you need to configure the styles using [arguments][],
but what if they're just a chunk of styles?
[arguments]: mixin#arguments
As a rule of thumb, extends are the best option when you're expressing a
relationship between semantic classes (or other semantic selectors). Because an
element with class `.error--serious` *is an* error, it makes sense for it to
extend `.error`. But for non-semantic collections of styles, writing a mixin can
avoid cascade headaches and make it easier to configure down the line.
<% fun_fact do %>
Most web servers compress the CSS they serve using an algorithm that's very good
at handling repeated chunks of identical text. This means that, although mixins
may produce more CSS than extends, they probably won't substantially increase
the amount your users need to download. So choose the feature that makes the
most sense for your use-case, not the one that generates the least CSS!
[gzip]: https://en.wikipedia.org/wiki/Gzip
<% end %>
## Limitations
### Disallowed Selectors
<% impl_status dart: true, libsass: false, ruby: false, feature: "No Compound Extensions" do %>
LibSass and Ruby Sass currently allow compound selectors like `.message.info`
to be extended. However, this behavior doesn't match the definition of
`@extend`: instead of styling elements that match the extending selector as
though it had `class="message info"`, which would be affected by style rules
that included either `.message` *or* `.info`, it only styled them with rules
that included both `.message` *and* `info`.
In order to keep the definition of `@extend` straightforward and
understandable, and to keep the implementation clean and efficient, that
behavior is now deprecated and will be removed from future versions.
See [the breaking change page][] for more details.
[the breaking change page]: ../breaking-changes/extend-compound
<% end %>
Only *simple selectors*—individual selectors like `.info` or `a`—can be
extended. If `.message.info` could be extended, the definition of `@extend` says
that elements matching the extender would be styled as though they matched
`.message.info`. That's just the same as matching both `.message` and `.info`,
so there wouldn't be any benefit in writing that instead of
`@extend .message, .info`.
Similarly, if `.main .info` could be extended, it would do (almost) the same
thing as extending `.info` on its own. The subtle differences aren't worth the
confusion of looking like it's doing something substantially different, so this
isn't allowed either.
<% example(autogen_css: false) do %>
.alert {
@extend .message.info;
// ^^^^^^^^^^^^^
// Error: Write @extend .message, .info instead.
@extend .main .info;
// ^^^^^^^^^^^
// Error: write @extend .info instead.
}
===
.alert
@extend .message.info
// ^^^^^^^^^^^^^
// Error: Write @extend .message, .info instead.
@extend .main .info
// ^^^^^^^^^^^
// Error: write @extend .info instead.
<% end %>
### HTML Heuristics
When `@extend` [interleaves complex selectors][], it doesn't generate all
possible combinations of ancestor selectors. Many of the selectors it could
generate are unlikely to actually match real HTML, and generating them all would
make stylesheets way too big for very little real value. Instead, it uses
a [heuristic][]: it assumes that each selector's ancestors will be
self-contained, without being interleaved with any other selector's ancestors.
[interleaves complex selectors]: #how-it-works
[heuristic]: https://en.wikipedia.org/wiki/Heuristic
<% example do %>
header .warning li {
font-weight: bold;
}
aside .notice dd {
// Sass doesn't generate CSS to match the in
//
//
//
//
//
// because matching all elements like that would require us to generate nine
// new selectors instead of just two.
@extend li;
}
===
header .warning li
font-weight: bold
aside .notice dd
// Sass doesn't generate CSS to match the in
//
//
//
//
//
// because matching all elements like that would require us to generate nine
// new selectors instead of just two.
@extend li
<% end %>
### Extend in `@media`
While `@extend` is allowed within [`@media` and other CSS at-rules][], it's not
allowed to extend selectors that appear outside its at-rule. This is because the
extending selector only applies within the given media context, and there's no
way to make sure that restriction is preserved in the generated selector without
duplicating the entire style rule.
[`@media` and other CSS at-rules]: css
<% example(autogen_css: false) do %>
@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;
}
===
@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
<% end %>