Skip to content

Sass @extend and Inheritance — Reusing Selector Rules

DodaTech Updated 2026-06-28 5 min read

In this tutorial, you will learn about Sass @extend and Inheritance. We cover key concepts, practical examples, and best practices to help you master this topic.

Sass @extend allows one selector to inherit styles from another selector, grouping selectors together in the compiled CSS and reducing file size by avoiding duplicated declarations.

What You'll Learn

You will learn how to use @extend to share styles between selectors, understand the difference between @extend and mixins, distinguish placeholder selectors, and avoid common pitfalls like extended chains.

Why It Matters

Extend produces smaller CSS files than mixins when multiple selectors share identical styles. DodaTech's component library uses placeholder extensions for shared button and card states, reducing compiled CSS by ~15 percent.

Real-World Use

Durga Antivirus Pro uses @extend with placeholder selectors for shared notification styles -- success, warning, error banners all extend a base placeholder rather than duplicating the same declarations.

flowchart LR
    A[Mixins] --> B[Extend]
    B --> C[Placeholder Selectors]
    B --> D[Selector Grouping]
    B --> E[Chains]
    B --> F[Limits]
    style B fill:#c69,stroke:#c69,color:#fff
    style C fill:#22c55e,stroke:#16a34a,color:#fff

Basic @extend

.error {
  border: 1px solid #dc2626;
  background: #fee2e2;
  color: #dc2626;
  padding: 1rem;
  border-radius: 4px;
}

.serious-error {
  @extend .error;
  font-weight: 700;
  border-width: 2px;
}

Compiles to:

.error, .serious-error {
  border: 1px solid #dc2626;
  background: #fee2e2;
  color: #dc2626;
  padding: 1rem;
  border-radius: 4px;
}

.serious-error {
  font-weight: 700;
  border-width: 2px;
}

Expected output: The extending selector is grouped with the original selector in a comma-separated rule, avoiding duplicated declarations.

Placeholder Selectors (%)

%button-base {
  display: inline-block;
  padding: 0.5rem 1rem;
  border: none;
  border-radius: 4px;
  font-size: 1rem;
  cursor: pointer;
}

.btn-primary {
  @extend %button-base;
  background: #7c3aed;
  color: white;
}

.btn-secondary {
  @extend %button-base;
  background: #e5e7eb;
  color: #374151;
}

Compiles to:

.btn-primary, .btn-secondary {
  display: inline-block;
  padding: 0.5rem 1rem;
  border: none;
  border-radius: 4px;
  font-size: 1rem;
  cursor: pointer;
}

.btn-primary {
  background: #7c3aed;
  color: white;
}

.btn-secondary {
  background: #e5e7eb;
  color: #374151;
}

Expected output: Placeholder selectors (prefixed with %) do not appear in the compiled CSS on their own; only the extending selectors appear.

Extending Multiple Selectors

%focus-ring {
  outline: 2px solid #7c3aed;
  outline-offset: 2px;
}

%rounded-corners {
  border-radius: 6px;
}

.card {
  @extend %focus-ring, %rounded-corners;
  background: white;
  padding: 1rem;
  box-shadow: 0 1px 3px rgba(0,0,0,0.1);
}

Compiles to:

.card {
  outline: 2px solid #7c3aed;
  outline-offset: 2px;
  border-radius: 6px;
  background: white;
  padding: 1rem;
  box-shadow: 0 1px 3px rgba(0,0,0,0.1);
}

Expected output: A selector can extend multiple placeholders in a comma-separated list.

Extend vs Mixin Decision

// Use @extend when selectors are conceptually related
%message-shared {
  padding: 1rem;
  border-radius: 4px;
  margin-bottom: 1rem;
}

.success { @extend %message-shared; background: #dcfce7; }
.error { @extend %message-shared; background: #fee2e2; }

// Use @mixin when values need to be parameterized
@mixin message-variant($bg, $color, $border) {
  padding: 1rem;
  border-radius: 4px;
  background: $bg;
  color: $color;
  border: 1px solid $border;
}

.success-ruby {
  @include message-variant(#dcfce7, #166534, #bbf7d0);
}

Compiles to:

.success, .error {
  padding: 1rem;
  border-radius: 4px;
  margin-bottom: 1rem;
}
.success { background: #dcfce7; }
.error { background: #fee2e2; }

.success-ruby {
  padding: 1rem;
  border-radius: 4px;
  background: #dcfce7;
  color: #166534;
  border: 1px solid #bbf7d0;
}

Expected output: Extend groups selectors (smaller CSS). Mixin duplicates output (more CSS) but supports dynamic values.

Common Mistakes

1. Extending Nested Selectors

Extending a deeply nested selector creates unexpected selector combinations. Always extend top-level classes or placeholders.

2. Extending Across Media Queries

@extend does not work across @media blocks. A selector defined inside one media query cannot be extended inside another.

3. Creating Long Extension Chains

Extending a selector that itself extends another selector creates a chain: .c extends .b extends .a. This leads to bloated selector lists.

4. Extending Concrete Classes vs Placeholders

Extending a concrete class (with a dot) makes that class part of the public API; changing it later can break extenders. Placeholders avoid this coupling.

5. Not Using % Placeholders

Without placeholder selectors, @extend creates unwanted CSS for the base class. Placeholders generate no output unless extended.

Practice Questions

  1. What character denotes a placeholder selector? The percent sign (%). Placeholders only appear in compiled CSS when extended.

  2. How does @extend differ from @mixin in output? @extend groups selectors into one rule (less CSS), while @mixin duplicates declarations (more CSS).

  3. Can you extend a selector inside a media query? No. @extend cannot cross @media boundaries. Each media query context is separate.

  4. What happens when you extend a placeholder that extends another placeholder? Both placeholders resolve their styles into the final extending selector via the chain.

  5. When should you prefer @mixin over @extend? Use @mixin when you need parameterized values or when the selector relationship is not conceptual.

Challenge

Take a CSS file with 4 button variants that each repeat the same base button styles (padding, border, font-size). Use @extend with a placeholder to eliminate the repetition while keeping variant-specific background colors.

FAQ

Can @extend be used with descendant selectors?

Yes, but it creates complex selector combinations. For example, extending .parent .child produces unexpected results. Stick to simple selectors.

Does @extend affect file size?

Positively. Extend groups selectors and removes duplicate declarations, reducing CSS file size compared to duplicated rules.

Can I use @extend inside a mixin?

Yes. Mixins can contain @extend rules. This is useful when a mixin needs to apply base styles from a placeholder.

What happens if the extended selector does not exist?

Sass throws a compilation error. The extended selector must be defined before it is used.

Is @extend same as CSS inherit?

No. Inherit inherits computed values at runtime from the parent element. @extend duplicates selector lists at compile time.

Mini Project

Take 6 notification component variants (success, error, warning, info, success-banner, error-banner) and use @extend with placeholders to share base styles. Ensure no placeholder appears in the compiled output.

What's Next

After mastering inheritance, learn about Placeholder Selectors for creating private reusable styles. Then explore Control Directives for conditional style generation.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro