@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一个选择器应该继承另一个选择器的样式。

当一个类扩展另一个类时,Sass样式化所有匹配扩展器的元素,就好像它们也匹配被扩展的类一样。当一个类选择器扩展另一个类时,它的工作原理与将扩展类添加到HTML中已有扩展类的每个元素一样。您只需编写class="error--serious", Sass将确保它的样式与class="error"一样。

当然,选择器并不只是在样式规则中单独使用。Sass知道扩展选择器使用的所有地方。这样可以确保元素的样式与扩展选择器匹配。

扩展是在其余所有的样式(特别是父选择器)编译完成之后再编译的。这意味着@extend .error,它不会影响内部的选择器.error { &__icon { ... } }。这也意味着SassScript中的父选择器不能看到扩展后的结果。

工作原理

与将样式复制到当前样式规则的mixin不同,@extend更新了包含扩展选择器的样式规则,以便它们也包含扩展选择器。扩展选择器时,Sass做了智能统一处理:

  • 它不会生成像#main#footer这样的选择器,这些选择器匹配不到任何元素。
  • 它确保复杂的选择器是交错的,这样无论嵌套HTML元素的顺序如何,它们都可以工作。
  • 它尽可能地减少冗余选择器,同时仍然确保选择器的特性大于或等于被扩展的选择器的特性。
  • 它知道一个选择器何时匹配另一个选择器所做的一切,并可以将它们组合在一起。
  • 它智能地处理组合选择器通用选择器:not选择器

您可以通过使用选择器函数直接使用Sass的智能统一功能!selector-unify()返回一个匹配两个选择器的交集的选择器,而selector-extend()的工作原理与@extend类似,但只在一个选择器上工作。

因为@extend更新包含扩展选择器的样式规则,所以它们在层叠计算中优先级更高,这取决于扩展选择器的样式规则出现在何处,而不是@extend出现在何处。这可能会令人困惑,但请记住:如果将扩展类添加到HTML中,这些规则的优先级将是相同的!

占位选择器

有时候,您想编写一个只打算扩展的样式规则。在这种情况下,您可以使用占位符选择器,以%开头的类选择器,而不是以.开头。CSS输出中不包含任何包含占位符的选择器,但会输出继承了该占位符选择器的选择器。

强制和可选扩展

通常,如果@extend不匹配样式表中的任何选择器,Sass将产生一个错误。这有助于避免输入错误或扩展选择器名称修改了而继承时使用时却没有修改的情况。扩展选择器必须是存在的,这是强制性的。

不过,这可能并不总是你想要的。如果您希望@extend在扩展选择器不存在的情况下什么也不做,只需在末尾添加!optional即可。

Extends or Mixins?

Extends和mixin都是在Sass中封装和复用样式的方法,这自然会产生何时使用哪个问题。当您需要使用参数配置样式时,mixin显然是更合适的,但是如果它们只是样式块呢?

根据经验,在表示语义类(或其他语义选择器)之间的关系时,extends是最佳选择。因为带有.error--erious类的元素也可表示错误的样式,所以扩展.error是有意义的。但是对于非语义的样式集合,编写mixin可以避免级联问题,并使其更容易配置。

大多数web服务器使用一种非常擅长处理重复、相同文本块的算法来压缩它们所提供的CSS。这意味着,尽管mixin生成的CSS可能比extend多,但它们可能不会显著增加用户下载的数量。因此,选择对您的用例最有意义的特性,而不是生成最少CSS的特性!

限制

禁止使用的选择器

兼容性:Dart Sass ✓ |LibSass ✗|Ruby Sass ✗

LibSass和Ruby Sass目前允许@extend .message.info这样的语句。但是,此行为与@extend的定义不匹配,如class ="message info"的元素,它将受到包含.message.info的样式规则的影响。
为了保持@extend的定义简单易懂,并保持实现干净高效,现在不赞成这种行为,并将从未来的版本中删除。

有关详细信息,请参阅重大改变的更改页面。

只能像.infoa这样简单的选择器可以被扩展。如果.message.info可以被扩展,那么@extend的定义表示,与扩展器匹配的元素将被设计成与.message.info匹配的样式。这和匹配.message.info是一样的,所以用它代替@extend .message,.info没有任何好处。

类似地,如果.main .info可以被扩展,它将(几乎)做与扩展.info相同的事情。这些细微的差别不值得让人觉得它在做一些本质上不同的事情,所以这也是不允许的。

启发式HTML

@extend交错复杂的选择器时,它不会生成所有可能的祖先选择器组合。它可能生成的许多选择器实际上不太可能匹配真实的HTML,并且生成它们都将使样式表太大而没有实际价值。相反,它使用启发式算法:它假设每个选择器的祖先都是自包含的,而不与任何其他选择器的祖先交叉。

在@media中使用扩展

虽然@extend允许在@media和其他CSS @规则中使用,但不允许扩展出现在其@规则之外的选择器。这是因为扩展选择器只应用于给定的媒体上下文中,而且无法确保在不复制整个样式规则的情况下将限制保留在生成的选择器中。

上次更新: 2019-11-5 4:49:11 PM