Sass offers powerful tools to manage styles more efficiently, among which @extend and inheritance stand out. These features allow you to share styles across different selectors, reducing redundancy and maintaining consistency. This guide explores how to use @extend and inheritance in Sass to create cleaner, more maintainable stylesheets.

What is @extend in Sass?

The @extend directive allows one selector to inherit the styles of another. This means you can apply the styles of a base selector to multiple other selectors, promoting style reuse and reducing redundancy.

Example:

.button {
  padding: 10px 20px;
  background-color: blue;
  color: white;
  border: none;
  border-radius: 5px;
}

.primary-button {
  @extend .button;
  background-color: darkblue;
}

Compiled CSS:

.button, .primary-button {
  padding: 10px 20px;
  background-color: blue;
  color: white;
  border: none;
  border-radius: 5px;
}

.primary-button {
  background-color: darkblue;
}

Benefits of Using @extend:

  1. Reduces Redundancy: Share styles between selectors without duplicating code.
  2. Consistent Styling: Ensure consistent styles across different elements by inheriting common base styles.
  3. Improved Maintainability: Update styles in one place, propagating changes across all selectors that extend the base style.

How to Use @extend and Inheritance:

Basic Inheritance:

Use @extend to allow one selector to inherit the styles of another.

Example:

// Define base styles
.notice {
  padding: 15px;
  margin: 10px 0;
  border: 1px solid transparent;
  border-radius: 4px;
}

// Extend base styles
.success {
  @extend .notice;
  background-color: #dff0d8;
  border-color: #d6e9c6;
}

.error {
  @extend .notice;
  background-color: #f2dede;
  border-color: #ebccd1;
}

Compiled CSS:

.notice, .success, .error {
  padding: 15px;
  margin: 10px 0;
  border: 1px solid transparent;
  border-radius: 4px;
}

.success {
  background-color: #dff0d8;
  border-color: #d6e9c6;
}

.error {
  background-color: #f2dede;
  border-color: #ebccd1;
}
Using Placeholders with %extend:

Placeholders, denoted by %, are special selectors that only exist to be extended. They do not generate any CSS on their own.

Example:

// Define a placeholder
%message {
  padding: 10px;
  margin: 5px 0;
  border: 1px solid #ccc;
}

// Extend the placeholder
.info {
  @extend %message;
  background-color: #d9edf7;
  border-color: #bce8f1;
}

.warning {
  @extend %message;
  background-color: #fcf8e3;
  border-color: #faebcc;
}

Compiled CSS:

.info, .warning {
  padding: 10px;
  margin: 5px 0;
  border: 1px solid #ccc;
}

.info {
  background-color: #d9edf7;
  border-color: #bce8f1;
}

.warning {
  background-color: #fcf8e3;
  border-color: #faebcc;
}
Combining @extend with Nested Selectors:

@extend works seamlessly with nested selectors, allowing you to extend nested styles.

Example:

// Define nested base styles
.panel {
  border: 1px solid #ddd;
  padding: 10px;
  .panel-heading {
    font-weight: bold;
  }
  .panel-body {
    padding: 10px;
  }
}

// Extend nested styles
.card {
  @extend .panel;
}

Compiled CSS:

.panel, .card {
  border: 1px solid #ddd;
  padding: 10px;
}

.panel .panel-heading, .card .panel-heading {
  font-weight: bold;
}

.panel .panel-body, .card .panel-body {
  padding: 10px;
}
Avoiding Specificity Issues:

While @extend is powerful, it can sometimes lead to specificity issues if overused or misused. Be mindful of how selectors are combined and consider using mixins for more complex styles.

Example:

// Use `@extend` for simple base styles
%button-base {
  padding: 10px 20px;
  border-radius: 5px;
}

// Use mixins for more complex scenarios
@mixin button-variant($bg-color) {
  background-color: $bg-color;
  color: #fff;
}

.button-primary {
  @extend %button-base;
  @include button-variant(blue);
}

.button-secondary {
  @extend %button-base;
  @include button-variant(green);
}

Compiled CSS:

.button-primary, .button-secondary {
  padding: 10px 20px;
  border-radius: 5px;
}

.button-primary {
  background-color: blue;
  color: #fff;
}

.button-secondary {
  background-color: green;
  color: #fff;
}
Organizing Extensions and Inheritance:

Organize your base styles and extensions logically to maintain a clean and readable codebase.

Example Directory Structure:

scss/
  base/
    _buttons.scss
    _notifications.scss
  components/
    _cards.scss
    _panels.scss
  main.scss

base/_buttons.scss:

%button-base {
  padding: 10px 20px;
  border-radius: 5px;
}

components/_cards.scss:

.card {
  @extend %button-base;
  background-color: #fff;
  border: 1px solid #ddd;
}

main.scss:

@import 'base/buttons';
@import 'components/cards';

Best Practices for Using @extend:

  1. Use Placeholders: Prefer placeholders over standard selectors for shared styles to prevent unwanted CSS output.
  2. Keep Extensions Simple: Avoid complex extensions that can lead to specificity and maintenance issues.
  3. Combine with Mixins: Use mixins for more complex, reusable styles that require parameters or need to be included conditionally.
  4. Organize by Functionality: Group related styles and extensions logically to keep your stylesheets organized and maintainable.

Conclusion:

Sass @extend and inheritance provide powerful tools for sharing and reusing styles across different selectors. By leveraging these features, you can create efficient, maintainable, and consistent stylesheets. Using @extend along with placeholders and combining it with mixins when necessary will help you manage complex styles effectively and streamline your CSS development workflow.