Sass 继承扩展 #

什么是 @extend? #

@extend 指令允许一个选择器继承另一个选择器的样式,实现样式的复用和继承。

scss
.message {
  border: 1px solid #ccc;
  padding: 10px;
  color: #333;
}

.success {
  @extend .message;
  border-color: green;
}

.error {
  @extend .message;
  border-color: red;
}

基本语法 #

scss
.selector1 {
  // 基础样式
}

.selector2 {
  @extend .selector1;
  // 额外样式
}

编译结果 #

基本继承 #

scss
.message {
  padding: 10px;
  border: 1px solid #ccc;
}

.success {
  @extend .message;
  border-color: green;
}

// 编译后
.message, .success {
  padding: 10px;
  border: 1px solid #ccc;
}

.success {
  border-color: green;
}

多重继承 #

scss
.message {
  padding: 10px;
}

.important {
  font-weight: bold;
}

.error {
  @extend .message;
  @extend .important;
  color: red;
}

// 编译后
.message, .error {
  padding: 10px;
}

.important, .error {
  font-weight: bold;
}

.error {
  color: red;
}

链式继承 #

scss
.message {
  padding: 10px;
}

.success {
  @extend .message;
  border-color: green;
}

.success-large {
  @extend .success;
  font-size: 20px;
}

// 编译后
.message, .success, .success-large {
  padding: 10px;
}

.success, .success-large {
  border-color: green;
}

.success-large {
  font-size: 20px;
}

占位符选择器 #

什么是占位符选择器? #

% 开头的选择器称为占位符选择器,它不会单独编译输出,只有被 @extend 继承时才会生成样式。

scss
// 占位符选择器
%button-base {
  display: inline-block;
  padding: 10px 20px;
  border: none;
  cursor: pointer;
}

// 不会被编译输出
.button-primary {
  @extend %button-base;
  background-color: blue;
}

.button-secondary {
  @extend %button-base;
  background-color: gray;
}

// 编译后
.button-primary, .button-secondary {
  display: inline-block;
  padding: 10px 20px;
  border: none;
  cursor: pointer;
}

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

.button-secondary {
  background-color: gray;
}

占位符 vs 类选择器 #

scss
// 类选择器:会被编译输出
.button {
  padding: 10px;
}

.btn-primary {
  @extend .button;
}

// 编译后
.button, .btn-primary {
  padding: 10px;
}

// 占位符选择器:不会被编译输出
%button {
  padding: 10px;
}

.btn-secondary {
  @extend %button;
}

// 编译后(没有 %button)
.btn-secondary {
  padding: 10px;
}

@extend vs @mixin #

使用场景对比 #

特性 @extend @mixin
输出方式 合并选择器 复制样式
文件大小 较小 较大
参数支持 不支持 支持
媒体查询 有限制 无限制
适用场景 相同样式,无参数 需要参数或灵活配置

@extend 示例 #

scss
%flex-center {
  display: flex;
  justify-content: center;
  align-items: center;
}

.modal {
  @extend %flex-center;
}

.overlay {
  @extend %flex-center;
}

// 编译后(合并选择器)
.modal, .overlay {
  display: flex;
  justify-content: center;
  align-items: center;
}

@mixin 示例 #

scss
@mixin flex($justify: center, $align: center) {
  display: flex;
  justify-content: $justify;
  align-items: $align;
}

.modal {
  @include flex;
}

.overlay {
  @include flex(space-between);
}

// 编译后(复制样式)
.modal {
  display: flex;
  justify-content: center;
  align-items: center;
}

.overlay {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

高级用法 #

继承复杂选择器 #

scss
// 继承带伪类的选择器
.link {
  color: blue;
  
  &:hover {
    text-decoration: underline;
  }
}

.button-link {
  @extend .link;
  background: none;
  border: none;
}

// 编译后
.link, .button-link {
  color: blue;
}

.link:hover, .button-link:hover {
  text-decoration: underline;
}

.button-link {
  background: none;
  border: none;
}

继承嵌套选择器 #

scss
.container {
  .item {
    padding: 10px;
  }
}

.special-container {
  @extend .container;
}

// 编译后
.container .item, .special-container .item {
  padding: 10px;
}

使用 !optional #

当继承的选择器不存在时,避免报错:

scss
.element {
  @extend .non-existent !optional;
  // 不会报错,也不会输出任何内容
}

实际应用示例 #

按钮系统 #

scss
%button-base {
  display: inline-block;
  padding: 10px 20px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 14px;
  font-weight: 500;
  text-align: center;
  text-decoration: none;
  transition: all 0.2s ease;
  
  &:hover {
    opacity: 0.9;
  }
  
  &:active {
    opacity: 0.8;
  }
  
  &:disabled {
    opacity: 0.5;
    cursor: not-allowed;
  }
}

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

.btn-secondary {
  @extend %button-base;
  background-color: #95a5a6;
  color: white;
}

.btn-success {
  @extend %button-base;
  background-color: #2ecc71;
  color: white;
}

.btn-danger {
  @extend %button-base;
  background-color: #e74c3c;
  color: white;
}

.btn-outline {
  @extend %button-base;
  background-color: transparent;
  border: 2px solid #3498db;
  color: #3498db;
}

表单元素 #

scss
%form-element {
  width: 100%;
  padding: 10px 15px;
  border: 1px solid #ddd;
  border-radius: 4px;
  font-size: 14px;
  transition: border-color 0.2s;
  
  &:focus {
    outline: none;
    border-color: #3498db;
  }
}

.input-text {
  @extend %form-element;
}

.input-email {
  @extend %form-element;
}

.input-password {
  @extend %form-element;
}

.textarea {
  @extend %form-element;
  min-height: 100px;
  resize: vertical;
}

.select {
  @extend %form-element;
  appearance: none;
  background-image: url("data:image/svg+xml,...");
  background-repeat: no-repeat;
  background-position: right 10px center;
}

消息提示 #

scss
%alert-base {
  padding: 15px 20px;
  border-radius: 4px;
  margin-bottom: 15px;
  
  &::before {
    content: "";
    margin-right: 10px;
  }
}

.alert-success {
  @extend %alert-base;
  background-color: #d4edda;
  color: #155724;
  border: 1px solid #c3e6cb;
}

.alert-danger {
  @extend %alert-base;
  background-color: #f8d7da;
  color: #721c24;
  border: 1px solid #f5c6cb;
}

.alert-warning {
  @extend %alert-base;
  background-color: #fff3cd;
  color: #856404;
  border: 1px solid #ffeeba;
}

.alert-info {
  @extend %alert-base;
  background-color: #d1ecf1;
  color: #0c5460;
  border: 1px solid #bee5eb;
}

卡片组件 #

scss
%card-base {
  background-color: white;
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  overflow: hidden;
}

.card {
  @extend %card-base;
  
  &__header {
    padding: 20px;
    border-bottom: 1px solid #eee;
  }
  
  &__body {
    padding: 20px;
  }
  
  &__footer {
    padding: 15px 20px;
    background-color: #f9f9f9;
  }
}

.card-compact {
  @extend %card-base;
  
  .card__header {
    padding: 10px 15px;
  }
  
  .card__body {
    padding: 15px;
  }
}

@extend 的限制 #

媒体查询限制 #

scss
// 错误:不能跨媒体查询继承
.container {
  width: 100%;
}

@media (min-width: 768px) {
  .container {
    @extend .container;  // 错误!
  }
}

// 正确:使用 @mixin
@mixin container-width {
  width: 100%;
}

.container {
  @include container-width;
}

@media (min-width: 768px) {
  .container {
    @include container-width;
  }
}

循环继承 #

scss
// 错误:循环继承
.a {
  @extend .b;
}

.b {
  @extend .a;
}

最佳实践 #

1. 优先使用占位符选择器 #

scss
// 好:使用占位符
%button-base {
  padding: 10px;
}

.btn {
  @extend %button-base;
}

// 不好:使用类选择器
.button-base {
  padding: 10px;
}

.btn {
  @extend .button-base;
}

2. 避免过度继承 #

scss
// 好:适度使用
%base {
  padding: 10px;
}

.element {
  @extend %base;
}

// 不好:过度继承链
%a { padding: 10px; }
%b { @extend %a; margin: 10px; }
%c { @extend %b; border: 1px; }
%d { @extend %c; color: red; }

3. 配合 @mixin 使用 #

scss
// 基础样式用 @extend
%button-base {
  display: inline-block;
  cursor: pointer;
}

// 可变样式用 @mixin
@mixin button-color($bg, $color) {
  background-color: $bg;
  color: $color;
  
  &:hover {
    background-color: darken($bg, 10%);
  }
}

.btn-primary {
  @extend %button-base;
  @include button-color(#3498db, white);
}

4. 保持继承关系简单 #

scss
// 好:简单的继承关系
%base { }
.variant-a { @extend %base; }
.variant-b { @extend %base; }

// 不好:复杂的继承网络
%base { }
%variant-a { @extend %base; }
%variant-b { @extend %base; }
%variant-c { @extend %variant-a; }
%variant-d { @extend %variant-b; }

下一步 #

掌握了继承扩展后,继续学习 模块系统,深入了解 @use 和 @forward!

最后更新:2026-03-28