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会导致.title与h1合并为同样的样式。 - 在小范围的情况下,这看起来很方便,但随着项目的增长,
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频道。