@extend
在设计页面时,通常情况下,一个类应具有另一类的所有样式以及其自己的特定样式。例如,BEM方法鼓励使用与块或元素类相同的元素的修饰符类。但这会造成混乱的HTML,很容易因忘记同时包含两个类而产生错误,并且会在标记中引入非语义样式问题。
<div class="error error--serious">
Oh no! You've been hacked!
</div>
.error {
border: 1px #f00;
background-color: #fdd;
}
.error--serious {
border-width: 3px;
}
Sass的@extend
法则解决了这个问题。它写成@extend <selector>
,并告诉Sass一个选择器应该继承另一个选择器的样式。
SCSS 语法
.error {
border: 1px #f00;
background-color: #fdd;
&--serious {
@extend .error;
border-width: 3px;
}
}
Sass语法
.error
border: 1px #f00
background-color: #fdd
&--serious
@extend .error
border-width: 3px
CSS 输出
.error, .error--serious {
border: 1px #f00;
background-color: #fdd;
}
.error--serious {
border-width: 3px;
}
当一个类扩展另一个类时,Sass设置所有与扩展器匹配的元素的样式,就好像它们也与要扩展的类匹配。当一个类选择器扩展另一个类选择器时,它的工作原理就像您将扩展类添加到HTML中已经具有扩展类的每个元素中一样。您只需编写class="error--serious"
,Sass就会确保它的样式class="error"
也是如此。
当然,选择器不只是在样式规则中单独使用。Sass知道可以扩展使用选择器的任何地方。这样可以确保元素的样式设置完全相同,就像它们与扩展选择器匹配一样。
SCSS 语法
.error:hover {
background-color: #fee;
}
.error--serious {
@extend .error;
border-width: 3px;
}
Sass语法
.error:hover
background-color: #fee
.error--serious
@extend .error
border-width: 3px
CSS 输出
.error:hover, .error--serious:hover {
background-color: #fee;
}
.error--serious {
border-width: 3px;
}
Head️抬头!
在样式表的其余部分被编译后,即可解决扩展问题。特别是,它在解析父选择器之后发生。这意味着,如果您这样做@extend .error
,则不会影响中的内部选择器.error { &__icon { ... } }
。这也意味着SassScript中的父选择器看不到扩展的结果。
如何运作永久它是如何工作
与mixins不同,mixins将样式复制到当前样式规则中,而是 @extend
更新包含扩展选择器的样式规则,以便它们也包含扩展选择器。扩展选择器时,Sass会进行智能统一:
它永远不会生成
#main#footer
可能无法匹配任何元素的选择器。它确保交错复杂的选择器,以便无论嵌套HTML元素的顺序如何,它们都可以工作。
它会尽可能地修剪冗余选择器,同时仍要确保特异性大于或等于扩展子的特异性。
它知道一个选择器何时与另一个选择器相匹配,并且可以将它们组合在一起。
SCSS 语法
.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 `<div class="guide">` will be inside or
// outside `<div class="content">`, so Sass generates both to be safe.
.guide .info {
border: 1px solid rgba(#000, 0.8);
border-radius: 2px;
}
// Sass knows that every element matching "main.content" also matches ".content"
// and avoids generating unnecessary interleaved selectors.
main.content .info {
font-size: 0.8em;
}
Sass语法
.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 `<div class="guide">` will be inside or
// outside `<div class="content">`, so Sass generates both to be safe.
.guide .info
border: 1px solid rgba(#000, 0.8)
border-radius: 2px
// Sass knows that every element matching "main.content" also matches ".content"
// and avoids generating unnecessary interleaved selectors.
main.content .info
font-size: 0.8em
CSS 输出
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
,但在单个选择器上。
Head️抬头!
因为@extend
更新包含扩展选择器的样式规则,所以它们的样式在层叠中的优先级取决于扩展选择器的样式规则出现的位置,而不是基于@extend
出现的位置。这可能会造成混淆,但请记住:如果将扩展类添加到HTML中,这是那些规则的优先级 !
占位符选择器permalink占位符选择器
有时您想编写仅用于扩展的样式规则。在这种情况下,您可以使用占位符选择器,它们看起来像以%
而不是开头的类选择器.
。CSS输出中不包括任何包含占位符的选择器,但扩展它们的选择器则包括在内。
SCSS 语法
.alert:hover, %strong-alert {
font-weight: bold;
}
%strong-alert:hover {
color: red;
}
Sass语法
.alert:hover, %strong-alert
font-weight: bold
%strong-alert:hover
color: red
CSS 输出
.alert:hover {
font-weight: bold;
}
私人占位符永久链接私人占位符
与模块成员一样,可以通过以-
或开头的占位符选择器将其标记为私有_
。私有占位符选择器只能在定义它的样式表中扩展。对于任何其他样式表,看起来好像该选择器不存在。
扩展范围永久链接扩展范围
当一个样式表扩展了一个选择器时,该扩展将仅影响上游模块中编写的样式规则,即,该样式表使用该@use
规则或@forward
rule加载的模块,这些模块加载的模块,依此类推。这有助于使@extend
规则更具可预测性,确保规则仅影响编写时知道的样式。
Head️抬头!
如果您使用该@import
规则,扩展根本就没有作用域。它们不仅会影响您导入的每个样式表,还会影响每个导入样式表的样式表,以及这些样式表导入的所有其他内容,依此类推。没有@use
,扩展是全球性的。
强制性和可选性扩展永久链接强制性和可选性扩展
通常,如果一个@extend
与样式表中的选择器不匹配,则Sass会产生错误。这有助于防止输入错误或重命名选择器,而无需重命名从其继承的选择器。要求扩展选择器存在的扩展是强制性的。
不过,这可能并不总是您想要的。如果您不希望@extend
扩展选择器不存在,则只需添加!optional
到末尾即可。
扩展还是混入?固定链接扩展还是混入?
扩展和混合是Sass中封装和重用样式的两种方式,这自然引起了何时使用哪种样式的问题。当您需要使用参数配置样式时,显然必须使用Mixins,但是如果它们只是一大堆样式呢?
根据经验,在表达语义类(或其他语义选择器)之间的关系时,扩展是最佳选择。由于具有class的元素.error--serious
是错误,因此对其进行扩展有意义.error
。但是对于非语义样式集合,编写mixin可以避免级联的麻烦,并使配置线更加容易。
???? 有趣的事实:
大多数Web服务器使用一种非常擅长处理重复的相同文本块的算法来压缩它们提供的CSS。这意味着,尽管mixin生成的CSS可能比扩展的更多,但它们可能不会显着增加用户需要下载的数量。因此,请选择对您的用例最有意义的功能,而不是生成CSS最少的功能 !
局限性永久性局限性
不允许的选择器永久链接不允许的选择器
- Dart·Sass(Dart Sass)
- ✓
- LibSass
- ✗
- rubySass
- ✗
LibSass和Ruby Sass当前允许.message.info
扩展复合选择器。但是,此行为不匹配的定义@extend
:不是造型延伸的选择,就好像它有相匹配的元素class="message info"
,这由样式规则,包括任何影响.message
或者 .info
,它只是与规则,既包括他们的风格.message
和 info
。
为了使定义@extend
简单明了,易于理解,并使实施保持清洁和高效,现在不赞成使用该行为,并将在以后的版本中将其删除。
有关更多详细信息,请参见重大更改页面。
只能扩展简单的选择器(如.info
或的单个选择器a
)。如果.message.info
可以扩展,则的定义@extend
说匹配扩展器的元素将被设置为样式,就好像它们匹配了.message.info
。这与同时匹配.message
和 相同.info
,因此编写代替不会有任何好处@extend .message, .info
。
同样,如果.main .info
可以扩展,它将(几乎)与.info
自己扩展一样。细微的差别不值得看起来好像在做本质上不同的事情那样令人困惑,因此也不允许这样做。
SCSS 语法
.alert {
@extend .message.info;
// ^^^^^^^^^^^^^
// Error: Write @extend .message, .info instead.
@extend .main .info;
// ^^^^^^^^^^^
// Error: write @extend .info instead.
}
Sass语法
.alert
@extend .message.info
// ^^^^^^^^^^^^^
// Error: Write @extend .message, .info instead.
@extend .main .info
// ^^^^^^^^^^^
// Error: write @extend .info instead.
HTML启发式永久链接 HTML 启发式
当@extend
交错复杂的选择器时,它不会生成祖先选择器的所有可能组合。它可能生成的许多选择器不太可能实际匹配真实的HTML,而生成所有选择器会使样式表太大而几乎没有真正的价值。相反,它使用启发式方法:它假定每个选择器的祖先都是独立的,而不会与任何其他选择器的祖先交错。
SCSS 语法
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;
}
Sass语法
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
CSS 输出
header .warning li, header .warning aside .notice dd, aside .notice header .warning dd {
font-weight: bold;
}
扩展为@media永久链接扩展为 @media
虽然@extend
在@media
其他CSS规则中允许使用,但不允许扩展出现在其规则之外的选择器。这是因为扩展选择器仅适用于给定的媒体上下文,并且无法确保在不复制整个样式规则的情况下保留在生成的选择器中的限制。
SCSS 语法
@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;
}
Sass语法
@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