@extend
在设计页面时,经常会出现一个类应该具有另一个类的所有样式以及它自己的特定样式的情况。例如,
BEM
方法鼓励使用与块或元素类相同的元素的修饰符类。但这会造成 HTML 混乱,容易因忘记包含这两个类而出错,并且可能会将非语义样式问题带入您的标记中。
// html <div class="error error--serious"> Oh no! You've been hacked! </div> // style .error { border: 1px #f00; background-color: #fdd; } .error--serious { border-width: 3px; }
Sass
,它告诉 Sass 一个选择器应该继承另一个选择器的样式。
scss 语句 | css 语句 |
---|---|
.error { border: 1px #f00; background-color: #fdd; &--serious { |
.error, .error--serious { border: 1px #f00; background-color: #fdd; } .error--serious { border-width: 3px; } |
当一个类扩展另一个类时,Sass 对所有匹配扩展器的元素进行样式设置,就好像它们也匹配被扩展的类一样。当一个类选择器扩展另一个类选择器时,它的工作方式与您将扩展类添加到 HTML 中已经具有扩展类的每个元素一样。你可以只写
class="
error
--serious
"
,Sass 会确保它的样式就像它
class="error"
一样。
当然,选择器不仅仅用于样式规则。Sass 知道在使用选择器的任何地方进行扩展。这可确保您的元素的样式与扩展选择器完全匹配。
scss 语句 | css 语句 |
---|---|
.error:hover { background-color: #fee; } .error--serious { |
.error:hover, .error--serious:hover { background-color: #fee; } .error--serious { border-width: 3px; } |
⚠️注意!
在您的样式表的其余部分被编译后,扩展被解析。特别是,它发生在父选择器被解析之后。这意味着如果你,它不会影响
@extend .error.error{&__icon{...}}
。这也意味着 SassScript 中的父选择器看不到扩展的结果。
运作机制
与将样式复制到当前样式规则中的 mixins 不同,
-
它从不生成像
#main
、#footer
,这样可能无法匹配任何元素的选择器。 - 它确保复杂的选择器是交错的,因此无论 HTML 元素的嵌套顺序如何,它们都能正常工作。
- 它尽可能地修剪冗余选择器,同时仍然确保特异性大于或等于扩展器的特异性。
- 它知道一个选择器何时匹配另一个选择器,并且可以将它们组合在一起。
- 它智能地处理组合器、通用选择器和包含选择器的伪类。
scss 语句 | css 语句 |
---|---|
.content nav.sidebar { @extend .info; } // This won't be extended, because `p` is incompatible with `nav`. p.info { background-color: #dee9fc; } // There's no way to know whether ` |
p.info { background-color: #dee9fc; } .guide .info, .guide .content nav.sidebar, .content .guide nav.sidebar { border: 1px solid rgba(0, 0, 0, 0.8); border-radius: 2px; } main.content .info, main.content nav.sidebar { font-size: 0.8em; } |
您可以使用选择器功能直接访问 Sass 的智能统一!该selector.unify() 函数返回一个匹配两个选择器交集的选择器。但在单个选择器上,该selector.extend() 函数的工作方式与@extend 类似。
⚠️注意!
因为@extend 更新包含扩展选择器的样式规则,它们的样式在级联中的优先级取决于扩展选择器的样式规则出现的位置,而不是基于@extend 出现的位置。这可能会令人困惑,但请记住:如果您将扩展类添加到 HTML中,这些规则将具有相同的优先级!
占位符选择器
有时您想编写仅用于扩展的样式规则。在这种情况下,您可以使用占位符选择器,它以
%
开头代替
.
的类选择器。任何包含占位符的选择器,都不包含在 CSS 输出中,但包含扩展它们的选择器。
scss 语句 | css 语句 |
---|---|
.alert:hover, %strong-alert { font-weight: bold; } %strong-alert:hover { color: red; } |
.alert:hover { font-weight: bold; } |
私有占位符
与模块成员一样,占位符选择器可以通过以
_
,开始其名称来标记为私有。私有占位符选择器只能在定义它的样式表中扩展。对于任何其他样式表,它看起来好像该选择器不存在。
扩展范围
当一个样式表扩展选择器时,该扩展将只影响在上游模块中编写的样式规则,即该样式表使用
⚠️注意!
如果您使用@import 规则,那么扩展根本不受范围限制。它们不仅会影响您导入的每个样式表,还会影响导入您的样式表的每个样式表,以及这些样式表导入的所有其他内容,等等。没有@use ,扩展是全局的。
强制和可选扩展
通常,如果
不过,这可能并不总是你想要的。如果您不想在
扩展还是混合?
Extends 和 Mixins 都是 Sass 中封装和重用样式的两种方式,这自然提出了何时使用哪一种的问题。当您需要使用参数配置样式时,显然需要使用 Mixin ,但是如果它们只是一大堆样式怎么办?
根据经验,当您表达语义类(或其他语义选择器)之间的关系时,扩展是最佳选择。因为带有类的元素
.error--serious
是错误的,所以扩展它是有意义的
.error
。但是对于非语义的样式集合,编写一个 mixin 可以避免级联问题,并使其更容易配置。
限制
只有简单的选择器——像
.infoor
这样的单独的选择器——可以被扩展。如果
.message.info
可以扩展,则
.message.info
。这与同时匹配
.message
和
.info
相同,因此编写它而不是
@extend .message,.info
不会有任何好处。
同样,如果
.main .info
可以扩展,它将做(几乎)与扩展自身
.info
相同的事情。细微的差异不值得混淆,因为它看起来像是在做一些截然不同的事情,所以这也是不允许的。
.alert { @extend .message.info; // ^^^^^^^^^^^^^ // Error: Write @extend .message, .info instead. @extend .main .info; // ^^^^^^^^^^^ // Error: write @extend .info instead. }
HTML 启发式
当
scss 语句 | css 语句 |
---|---|
header .warning li { font-weight: bold; } aside .notice dd { // Sass doesn't generate CSS to match the <dd> in // // <header> // <aside> // <div class="warning"> // <div class="notice"> // <dd>...</dd> // </div> // </div> // </aside> // </header> // // because matching all elements like that would require us to generate nine // new selectors instead of just two. @extend li; } |
header .warning li, header .warning aside .notice dd, aside .notice header .warning dd { font-weight: bold; } |
扩展扩展@media
虽然
@media screen and (max-width: 600px) { .error--serious { @extend .error; // ^^^^^^ // Error: ".error" was extended in @media, but used outside it. } } .error { border: 1px #f00; background-color: #fdd; }