Sass @extend lets one selector inherit the styles of another by merging selectors in the compiled CSS. This page covers how extend works, placeholder selectors, !optional, module scope, when to prefer mixins, limitations, and five compiled examples.
01
Inherit
@extend
02
Merge
Selector lists
03
Silent
%placeholder
04
Optional
!optional
05
Vs mixins
When to choose
06
Practice
5 examples
Concept
What Is @extend?
Official docs: there are often cases when one class should have all the styles of another class, plus its own. Writing both classes in HTML (class="error error--serious") is cluttered and easy to forget.
Sass’s @extend rule is written @extend <selector>. It tells Sass that one selector should inherit the styles of another. When .error--serious extends .error, you can write only class="error--serious" in HTML and still get the base error styles.
Unlike mixins, extend does not copy properties into the current rule.
It updates rules that already mention the extended selector, adding the extender to those selector lists.
Sass extends everywhere the selector is used—including :hover and other compounds.
Extends are resolved after the rest of the stylesheet (including parent selectors).
💡
Beginner tip
Think of @extend as saying “this class is also that class.” Sass rewrites the CSS selectors so both share the same style rules.
Compiled CSS shares the base rule between .error and .error--serious, then adds the modifier-only declaration separately.
Mechanics
⚙️ How It Works
Official docs: when extending selectors, Sass does intelligent unification. It never generates impossible selectors (like #main#footer), interleaves complex selectors safely, trims redundancy, and handles combinators and many pseudo-classes.
Incompatible types are skipped (e.g. extending .info from nav will not touch p.info).
Cascade order follows where the extended rule appears—not where @extend is written.
Parent-selector nesting like .error { &__icon { … } } is not extended when you @extend .error (extends run after nesting is resolved).
💡
Selector functions
You can also use selector.unify() and selector.extend() from the Sass selector module for programmatic unification.
Silent classes
🚫 Placeholder Selectors
Official docs: when a style rule is only meant to be extended, use a placeholder selector—a class-like name that starts with % instead of ..
Selectors that include unused placeholders are omitted from CSS.
Extenders appear in the output in place of the placeholder.
Private placeholders start with - or _ and can only be extended in the same stylesheet (like private module members).
By default, if @extend matches nothing, Sass errors (protects against typos). Add !optional when a missing target should be ignored: @extend %theme-btn !optional.
Extension scope with @use
Official docs: when one stylesheet extends a selector, that extension only affects upstream modules loaded with @use / @forward (and their upstreams). That keeps extends predictable.
⚠️
Legacy @import
With deprecated @import, extensions are global across the import graph. Prefer @use for scoped, predictable extends.
Choose wisely
⚖️ Extends or Mixins?
Official rule of thumb: use @extend when you express a relationship between semantic classes (an .error--seriousis an error). For non-semantic style chunks—or anything that needs arguments—prefer a mixin.
Mixins can take arguments and @content; extends cannot.
Mixins may emit more CSS, but gzip/brotli usually handle repetition well.
Choose clarity over “smallest CSS” unless you have measured a problem.
Constraints
🚫 Limitations
Only simple selectors
You can extend simple selectors like .info or a—not compounds like .message.info or descendants like .main .info. Write @extend .message, .info instead.
HTML heuristics
When interleaving complex selectors, Sass does not generate every possible ancestor combination (that would explode CSS size). It assumes each selector’s ancestors are mostly self-contained.
Inside @media
You may use @extend inside @media, but you cannot extend a selector that appears outside that at-rule. Keep both the extender and the extended rule in the same media context.
Cheat Sheet
⚡ Quick Reference
Goal
Code
Inherit a class
@extend .error;
Extend several
@extend .message, .info;
Silent base
%btn { … } then @extend %btn;
Optional extend
@extend %theme !optional;
Semantic reuse
Prefer @extend
Configurable chunk
Prefer @mixin
Hands-On
Examples Gallery
Each example uses @extend at compile time. Open View Compiled CSS for verified output.
Intelligent merging adds extenders to matching rules.
Merge
4
✓
CSS ships
Shared declarations appear once with selector lists.
Watch Out
⚠️ Common Pitfalls
Cascade surprises — precedence follows the extended rule’s location, not the @extend line.
Expecting nested & to extend — extends run after nesting is resolved.
Compound extends — do not write @extend .a.b; extend simple selectors.
Cross-media extends — cannot extend a selector defined outside the current @media.
Overusing extend for utilities — mixins are often clearer for non-semantic chunks.
Pro Tips
💡 Best Practices
✅ Do
Extend for semantic “is-a” relationships
Prefer % placeholders for silent shared bases
Use !optional for soft theme hooks
Keep extends scoped with @use
Extend simple selectors only
❌ Don’t
Use extend as a substitute for every mixin
Extend compounds or descendant selectors
Extend across different @media contexts
Rely on global extends via legacy @import
Chase micro CSS savings over readable architecture
Summary
Key Takeaways
Knowledge Unlocked
Five things to remember about Sass @extend
Merge selectors for semantic inheritance—do not copy properties like a mixin.
5
Core concepts
📝01
Inherit
@extend selector
Share
🔀02
Merge
selector lists
Unify
🚫03
Silent
%placeholders
Base
🔒04
Safe
!optional
Guard
✓05
Semantic
else use mixins
Choose
❓ Frequently Asked Questions
It tells Sass that one selector should inherit the styles of another. Sass updates style rules that contain the extended selector so they also include the extending selector.
Mixins copy styles into the current rule. @extend merges selectors so shared styles appear once with a selector list. Use extends for semantic relationships; use mixins for configurable style chunks.
A selector that starts with % (like %message-shared). Rules that only use placeholders are omitted from CSS until something @extends them.
Normally @extend errors if the target selector is missing. Add !optional to silently do nothing when the extended selector does not exist.
No in modern Dart Sass. Only simple selectors can be extended. Write @extend .message, .info instead of @extend .message.info.
Yes, but you can only extend selectors defined inside the same at-rule. Extending a selector that appears outside the @media is an error.
Did you know?
Official Sass docs note that most servers gzip/brotli CSS very well—so mixins that repeat text often download almost as cheaply as extends. Pick the clearer tool for your design, not just the smaller output.
@extend merges selectors so semantic classes can share styles without duplicating HTML classes. Reach for placeholders and !optional when you need silent bases, and prefer mixins when styles need arguments or are not a true “is-a” relationship.