SASS中的继承

SASS中的继承

本文解释了SASS中的继承。

我们将通过实际例子来解释SASS中的继承。

YouTube Video

SASS中的继承

SASS中的继承(@extend)是一种机制,允许你将一个选择器的样式无重复地应用到另一个选择器上。由于相同的样式会被“合并”并输出到标记中的多个元素,生成的CSS不容易冗余;但如果使用不当,可能会导致意外的选择器合并。

基础:如何使用@extend

下面是一个基础示例,.btn--primary继承了.btn的样式。@extend是一条扩展目标选择器的指令。

 1// Base button styles
 2.btn {
 3  padding: 0.5rem 1rem;
 4  border-radius: 4px;
 5  border: 1px solid #ccc;
 6  background: white;
 7  color: #333;
 8}
 9
10/* Primary button extends the base .btn */
11.btn--primary {
12  @extend .btn;
13  background: #007bff;
14  color: white;
15}
  • 通过使用@extend.btn--primary继承了.btn的基础样式,只重写需要改变的部分。

生成的CSS

 1.btn, .btn--primary {
 2  padding: 0.5rem 1rem;
 3  border-radius: 4px;
 4  border: 1px solid #ccc;
 5  background: white;
 6  color: #333;
 7}
 8
 9.btn--primary {
10  background: #007bff;
11  color: white;
12}

最佳实践:使用占位符(%placeholder

占位符选择器 (%name) 是不会输出到 CSS 的选择器。它们被广泛使用,尤其是在需要在多个组件之间安全地共享仅用于继承的通用样式时。

 1// %placeholder will not be output directly
 2%card-base {
 3  padding: 1rem;
 4  border-radius: 6px;
 5  box-shadow: 0 1px 3px rgba(0,0,0,0.08);
 6  background: #fff;
 7}
 8
 9/* Components extend the placeholder */
10.card {
11  @extend %card-base;
12  border: 1px solid #eee;
13}
14
15.panel {
16  @extend %card-base;
17  border: 1px solid #ddd;
18}
  • .card.panel都继承自%card-base,这样可以共享公共样式,同时根据需要添加差异。

生成的CSS

 1.card, .panel {
 2  padding: 1rem;
 3  border-radius: 6px;
 4  box-shadow: 0 1px 3px rgba(0,0,0,0.08);
 5  background: #fff;
 6}
 7
 8.card {
 9  border: 1px solid #eee;
10}
11
12.panel {
13  border: 1px solid #ddd;
14}

多重继承(多个@extend

你可以同时继承多个占位符或类。虽然样式的可重用性得以提升,但必须注意追踪哪些规则与哪些选择器组合。

 1%btn-base {
 2  display: inline-block;
 3  padding: 0.5rem 1rem;
 4  border-radius: 3px;
 5}
 6
 7%btn-large {
 8  padding: 0.75rem 1.5rem;
 9  font-size: 1.125rem;
10}
11
12/* Composite button that extends both placeholders */
13.btn--lg {
14  @extend %btn-base;
15  @extend %btn-large;
16  background: #222;
17  color: #fff;
18}
  • 这是一个按钮同时继承两个占位符(一个用于‘基础’,一个用于‘尺寸’)的例子。
  • .btn--lg同时继承%btn-base%btn-large,结合了基础布局和更大的尺寸。

生成的CSS

1.btn--lg {
2  display: inline-block;
3  /* %btn-large overrides the padding from %btn-base */
4  padding: 0.75rem 1.5rem;
5  border-radius: 3px;
6  font-size: 1.125rem;
7  background: #222;
8  color: #fff;
9}

@extend的行为(合并机制)及“选择器爆炸”的注意事项

@extend会将所有匹配的选择器合并输出,有时会产生意外的选择器组合。

下面的例子展示了当同一个基础类在多个地方被扩展时,输出会变得多么庞大。

 1/* Many components extend .utility */
 2/* A generic utility class */
 3.utility {
 4  margin-bottom: 1rem;
 5}
 6
 7/* Nested selectors that extend .utility */
 8.header {
 9  @extend .utility;
10  .title {
11    font-weight: bold;
12  }
13}
14
15.footer {
16  @extend .utility;
17  .note {
18    color: #888;
19  }
20}
21
22.article {
23  @extend .utility;
24  .content {
25    line-height: 1.6;
26  }
27}
28
29.sidebar {
30  @extend .utility;
31  .section {
32    padding: 1rem;
33  }
34}
  • 当多个组件继承.utility时,选择器会合并到一起,在大型项目中可能会导致CSS臃肿。

生成的CSS

 1.utility,
 2.header,
 3.footer,
 4.article,
 5.sidebar {
 6  margin-bottom: 1rem;
 7}
 8
 9.header .title {
10  font-weight: bold;
11}
12
13.footer .note {
14  color: #888;
15}
16
17.article .content {
18  line-height: 1.6;
19}
20
21.sidebar .section {
22  padding: 1rem;
23}

@extend.class及元素选择器(标签)的对比——优先级与副作用

@extend 不仅可以应用于类选择器,也可以应用于元素选择器。然而,扩展元素会增加影响范围,提高规则被意外应用到不希望的位置的风险。

下面是一个扩展元素选择器的例子,以及它可能产生的影响。

 1/* Extending an element selector (not recommended) */
 2h1 {
 3  font-size: 2rem;
 4  margin-bottom: 0.5rem;
 5}
 6
 7/* If you extend h1, the resulting selector will include your class with h1 */
 8.title {
 9  @extend h1;
10  color: #333;
11}
12
13/* Output becomes:
14h1, .title { font-size: 2rem; margin-bottom: 0.5rem; }
15*/
  • 在此例中,继承元素选择器h1会导致.titleh1合并为同样的样式。
  • 在小范围的情况下,这看起来很方便,但随着项目的增长,h1 的规则可能会和 .title 意外地组合,导致样式变得更复杂、维护性降低。因此,最好以类和占位符为主来设计样式,这样更易于维护。

生成的CSS

1h1,
2.title {
3  font-size: 2rem;
4  margin-bottom: 0.5rem;
5}
6
7.title {
8  color: #333;
9}

@extend!optional 的使用场景

如果在 @extend 时指定 !optional,当继承目标不存在时可以避免报错。这在类库代码或者占位符根据条件定义的情况下特别有用。

下面的例子演示了如何用!optional安全地继承一个可能不存在的类。

1/* Try to extend a class that might not exist */
2.component {
3  @extend .maybe-existing !optional;
4  padding: 1rem;
5}
  • 如果 .maybe-existing 不存在,则不会发生任何事,直接跳过。希望安全尝试扩展时可以使用这一特性。

生成的CSS

1.component {
2  padding: 1rem;
3}

@extend 和 Mixin(@mixin/@include)的对比

@extend@mixin有时功能相似,但输出结果和使用场景各不相同。

  • @extend

    • 生成的CSS通过合并选择器来减少冗余。
    • 由于是在生成后合并选择器,可能会出现意想不到的组合。
    • 不能传递参数(不过可以通过组合占位符来补救这一点)。
  • @mixin / @include

    • 每次调用都会复制样式(导致输出冗余)。
    • 你可以传递参数,并嵌入条件判断或循环等逻辑。
    • 输出更具可控性,但文件体积会增加。

下面是一个用@mixin@extend实现同一按钮样式的对比。

 1/* Mixin approach */
 2@mixin btn-styles($bg, $color) {
 3  display: inline-block;
 4  padding: 0.5rem 1rem;
 5  background: $bg;
 6  color: $color;
 7  border-radius: 4px;
 8}
 9
10/* Use mixin */
11.btn {
12  @include btn-styles(white, #333);
13}
14
15.btn--primary {
16  @include btn-styles(#007bff, white);
17}
18
19/* Extend approach (shared placeholder) */
20%btn-base {
21  display: inline-block;
22  padding: 0.5rem 1rem;
23  border-radius: 4px;
24}
25
26.btn2 {
27  @extend %btn-base;
28  background: white;
29  color: #333;
30}
31
32.btn2--primary {
33  @extend %btn-base;
34  background: #007bff;
35  color: white;
36}
  • @mixin让你灵活插入样式,而@extend则高效合并输出,因此可根据实际场景选择使用哪一个。

生成的CSS

@mixin 的输出结果
 1.btn {
 2  display: inline-block;
 3  padding: 0.5rem 1rem;
 4  background: white;
 5  color: #333;
 6  border-radius: 4px;
 7}
 8
 9.btn--primary {
10  display: inline-block;
11  padding: 0.5rem 1rem;
12  background: #007bff;
13  color: white;
14  border-radius: 4px;
15}
@extend 的输出结果
 1.btn2,
 2.btn2--primary {
 3  display: inline-block;
 4  padding: 0.5rem 1rem;
 5  border-radius: 4px;
 6}
 7
 8.btn2 {
 9  background: white;
10  color: #333;
11}
12
13.btn2--primary {
14  background: #007bff;
15  color: white;
16}

实用指南

SASS 继承是一项提高样式可重用性的强大功能。但如果用法不当,会让样式合并变得复杂,降低可维护性。以下是在安全高效地使用继承时需要注意的要点。

  • 对于结构和布局等纯通用组件样式,应该使用占位符。另外,如果需要动态参数化,可以使用 @mixin
  • 应避免直接继承如 h1 这样的 HTML 元素。可能会出现未预期的选择器组合,从而生成意外的 CSS。
  • 使用BEM之类的命名规则或明确前缀来标识每个占位符的用途,有助于保证安全。
  • 在同一个文件内使用 @extend 更为安全。尤其是在大型项目中,建议在每个组件的范围内设计继承,以便更容易追踪继承关系。

总结

SASS 中的 @extend 功能是一种高效复用通用样式、确保设计一致性的便捷方式。然而,由于选择器组合很容易变得复杂,因此有必要在有限的范围内谨慎使用这一功能。通过用占位符选择器(%placeholder)分组共享样式,并在需要动态参数的部分使用 @mixin,可以保持设计简洁且易于维护。

您可以在我们的YouTube频道上使用Visual Studio Code跟随上述文章进行学习。 请也查看我们的YouTube频道。

YouTube Video