跳到主要内容

Extend

Extend 是 Less 的伪类,它将其放置在的选择器与匹配其引用的选择器合并。

发布v1.4.0

nav ul {
&:extend(.inline);
background: blue;
}

在上面的规则集中,:extend选择器将“扩展选择器”(nav ul)应用于.inline类“无论.inline类出现在哪里”。声明块将保持不变,但没有任何关于扩展的引用(因为扩展不是 CSS)。

所以以下内容:

nav ul {
&:extend(.inline);
background: blue;
}
.inline {
color: red;
}

输出

nav ul {
background: blue;
}
.inline,
nav ul {
color: red;
}

请注意,nav ul:extend(.inline)选择器输出为nav ul - 扩展在输出之前被删除,选择器块保持不变。如果在该块中没有放置属性,则它将从输出中删除(但扩展仍可能影响其它选择器)。

扩展语法

扩展可以附加到选择器或放置到规则集中。它看起来像一个带有选择器参数的伪类,后面可以选择跟随关键字all

示例:

.a:extend(.b) {
}

// 上面的块与下面的块执行相同的操作
.a {
&:extend(.b);
}
.c:extend(.d all) {
// 扩展所有“.d”的实例,例如“.x.d”或“.d.x”
}
.c:extend(.d) {
// 仅扩展选择器将输出为“.d”的实例
}

它可以包含一个或多个要扩展的类,用逗号分隔。

示例:

.e:extend(.f) {
}
.e:extend(.g) {
}

// 上面和下面执行相同的操作
.e:extend(.f, .g) {
}

附加到选择器的扩展

附加到选择器的扩展看起来像一个普通的带有选择器参数的伪类。选择器可以包含多个扩展子句,但所有扩展子句必须位于选择器的末尾。

  • 选择器后的扩展:pre:hover:extend(div pre)
  • 选择器和扩展之间允许有空格:pre:hover :extend(div pre)
  • 允许多个扩展:pre:hover:extend(div pre):extend(.bucket tr) - 请注意,这与pre:hover:extend(div pre, .bucket tr)相同
  • 不允许这样做:pre:hover:extend(div pre).nth-child(odd)。扩展必须是最后一个。

如果规则集包含多个选择器,则任何一个选择器都可以具有扩展关键字。一个规则集中具有扩展的多个选择器:

.big-division,
.big-bag:extend(.bag),
.big-bucket:extend(.bucket) {
// body
}

在规则集内扩展

可以使用 &:extend(selector) 语法将 Extend 放置在规则集的主体中。将 Extend 放置在主体中是将其放置在该规则集的每个选择器中的快捷方式。

主体内的 Extend:

pre:hover,
.some-class {
&:extend(div pre);
}

与在每个选择器后添加 Extend 完全相同:

pre:hover:extend(div pre),
.some-class:extend(div pre) {
}

扩展嵌套选择器

Extend 能够匹配嵌套选择器。按照 less:

示例:

.bucket {
tr {
// 带有目标选择器的嵌套规则集
color: blue;
}
}
.some-class:extend(.bucket tr) {
} // 嵌套规则集被识别

输出

.bucket tr,
.some-class {
color: blue;
}

本质上,Extend 查看编译后的 CSS,而不是原始的 less。

示例:

.bucket {
tr & {
// 带有目标选择器的嵌套规则集
color: blue;
}
}
.some-class:extend(tr .bucket) {
} // 嵌套规则集被识别

输出

tr .bucket,
.some-class {
color: blue;
}

使用 Extend 进行精确匹配

Extend 默认查找选择器之间的精确匹配。选择器是否使用前导星号并不重要。两个 nth 表达式具有相同的含义并不重要,它们需要具有相同的形式才能匹配。唯一的例外是属性选择器中的引号,less 知道它们具有相同的含义并匹配它们。

示例:

.a.class,
.class.a,
.class > .a {
color: blue;
}
.test:extend(.class) {
} // 这不会匹配上面的任何选择器

前导星号很重要。选择器 *.class.class 是等效的,但是 Extend 不会匹配它们:

*.class {
color: blue;
}
.noStar:extend(.class) {
} // 这不会匹配 *.class 选择器

输出

*.class {
color: blue;
}

伪类的顺序很重要。选择器 link:hover:visitedlink:visited:hover 匹配相同的元素集,但是 Extend 将它们视为不同的:

link:hover:visited {
color: blue;
}
.selector:extend(link:visited:hover) {
}

输出

link:hover:visited {
color: blue;
}

nth 表达式

Nth 表达式的形式很重要。Nth 表达式 1n+3n+3 是等效的,但是 Extend 不会匹配它们:

:nth-child(1n + 3) {
color: blue;
}
.child:extend(:nth-child(n + 3)) {
}

输出

:nth-child(1n + 3) {
color: blue;
}

属性选择器中的引号类型并不重要。

以下是等效的代码。

[title="identifier"] {
color: blue;
}
[title="identifier"] {
color: blue;
}
[title="identifier"] {
color: blue;
}

.noQuote:extend([title="identifier"]) {
}
.singleQuote:extend([title="identifier"]) {
}
.doubleQuote:extend([title="identifier"]) {
}

输出结果为:

[title="identifier"],
.noQuote,
.singleQuote,
.doubleQuote {
color: blue;
}

[title="identifier"],
.noQuote,
.singleQuote,
.doubleQuote {
color: blue;
}

[title="identifier"],
.noQuote,
.singleQuote,
.doubleQuote {
color: blue;
}

扩展“all”

当你在扩展参数中最后指定 all 关键字时,它告诉 Less 将该选择器作为另一个选择器的一部分进行匹配。选择器将被复制,然后仅匹配的选择器部分将被替换为扩展,从而创建一个新的选择器。

例如:

.a.b.test,
.test.c {
color: orange;
}
.test {
&:hover {
color: green;
}
}

.replacement:extend(.test all) {
}

输出结果为:

.a.b.test,
.test.c,
.a.b.replacement,
.replacement.c {
color: orange;
}
.test:hover,
replacement:hover {
color: green;
}

你可以将这种操作模式视为执行非破坏性搜索和替换。

使用扩展的选择器插值

扩展无法匹配包含变量的选择器。如果选择器包含变量,则扩展将忽略它。

但是,扩展可以附加到插值选择器上。

不会匹配包含变量的选择器:

@variable: .bucket;
@{variable} {
// 插值选择器
color: blue;
}
.some-class:extend(.bucket) {
} // 不起作用,没有找到匹配项

在目标选择器中带有变量的扩展不匹配任何内容:

.bucket {
color: blue;
}
.some-class:extend(@{variable}) {
} // 插值选择器不匹配任何内容
@variable: .bucket;

上述两个示例都编译为:

.bucket {
color: blue;
}

但是,附加到插值选择器的 :extend 可以工作:

.bucket {
color: blue;
}
@{variable}:extend(.bucket) {
}
@variable: .selector;

编译为:

.bucket,
.selector {
color: blue;
}

作用域 / 在 @media 中使用扩展

目前,在 @media 声明中的 :extend 仅匹配相同媒体声明中的选择器:

@media print {
.screenClass:extend(.selector) {
} // 媒体内部的扩展
.selector {
// 这将被匹配 - 它在相同的媒体中
color: black;
}
}
.selector { // 样式表的顶部 - 扩展忽略它
color: red;
}
@media screen {
.selector {
// 另一个媒体内的规则集 - 扩展忽略它
color: blue;
}
}

编译为:

@media print {
.selector,
.screenClass {
/* 同一媒体内的规则集被扩展 */
color: black;
}
}
.selector {
/* 样式表顶部的规则集被忽略 */
color: red;
}
@media screen {
.selector {
/* 另一个媒体内的规则集被忽略 */
color: blue;
}
}

注意:扩展不匹配嵌套的@media声明内的选择器:

@media screen {
.screenClass:extend(.selector) {
} // 媒体内的扩展
@media (min-width: 1023px) {
.selector {
// 嵌套媒体内的规则集 - 扩展忽略它
color: blue;
}
}
}

这将编译为:

@media screen and (min-width: 1023px) {
.selector {
/* 另一个嵌套媒体内的规则集被忽略 */
color: blue;
}
}

顶级扩展匹配所有内容,包括嵌套媒体内的选择器:

@media screen {
.selector {
/* 嵌套媒体内的规则集 - 顶级扩展有效 */
color: blue;
}
@media (min-width: 1023px) {
.selector {
/* 嵌套媒体内的规则集 - 顶级扩展有效 */
color: blue;
}
}
}

.topLevel:extend(.selector) {
} /* 顶级扩展匹配所有内容 */

编译为:

@media screen {
.selector,
.topLevel {
/* 媒体内的规则集被扩展 */
color: blue;
}
}
@media screen and (min-width: 1023px) {
.selector,
.topLevel {
/* 嵌套媒体内的规则集被扩展 */
color: blue;
}
}

重复检测

目前没有重复检测。

例如:

.alert-info,
.widget {
/* 声明 */
}

.alert:extend(.alert-info, .widget) {
}

输出:

.alert-info,
.widget,
.alert,
.alert {
/* 声明 */
}

扩展的用例

经典用例

经典用例是避免添加基础类。例如,如果你有

.animal {
background-color: black;
color: white;
}

并且你想要一个覆盖背景颜色的动物子类型,则有两个选项,首先更改你的 HTML

<a class="animal bear">Bear</a>
.animal {
background-color: black;
color: white;
}
.bear {
background-color: brown;
}

或者使用简化的 HTML 并在 less 中使用 extend。例如:

<a class="bear">Bear</a>
.animal {
background-color: black;
color: white;
}
.bear:extend(.animal) {
background-color: brown;
}

多个选择器

另一个用例是在多个选择器之间共享样式。例如,如果你有以下 HTML:

<button class="primary">Primary Button</button>
<button class="secondary">Secondary Button</button>

并且你想要两个按钮都具有相同的样式,则可以使用 extend:

.button {
border: 1px solid black;
padding: 10px;
}

.primary:extend(.button) {
background-color: blue;
color: white;
}

.secondary:extend(.button) {
background-color: gray;
color: black;
}

这将编译为:

.button,
.primary,
.secondary {
border: 1px solid black;
padding: 10px;
}

.primary {
background-color: blue;
color: white;
}

.secondary {
background-color: gray;
color: black;
}

继承

另一个用例是继承。例如,如果你有以下 HTML:

<div class="parent">
<div class="child"></div>
</div>

并且你想要子元素继承父元素的样式,则可以使用 extend:

.parent {
background-color: gray;
color: white;
}

.child:extend(.parent) {
font-size: 20px;
}

这将编译为:

.parent,
.child {
background-color: gray;
color: white;
}

.child {
font-size: 20px;
}

减少 CSS 大小

Mixin 将所有属性复制到选择器中,这可能会导致不必要的重复。因此,你可以使用 extends 而不是 mixins 将选择器移动到要使用的属性,这会导致生成的 CSS 更少。

示例 - 使用 mixin:

.my-inline-block() {
display: inline-block;
font-size: 0;
}
.thing1 {
.my-inline-block;
}
.thing2 {
.my-inline-block;
}

输出

.thing1 {
display: inline-block;
font-size: 0;
}
.thing2 {
display: inline-block;
font-size: 0;
}

示例(使用 extends):

.my-inline-block {
display: inline-block;
font-size: 0;
}
.thing1 {
&:extend(.my-inline-block);
}
.thing2 {
&:extend(.my-inline-block);
}

输出

.my-inline-block,
.thing1,
.thing2 {
display: inline-block;
font-size: 0;
}

合并样式 / 更高级的 Mixin

另一个用例是作为 mixin 的替代方案 - 因为 mixin 只能与简单选择器一起使用,如果你有两个不同的 HTML 块,但需要将相同的样式应用于两个块,你可以使用 extends 关联两个区域。

示例:

li.list > a {
// 列表样式
}
button.list-style {
&:extend(li.list > a); // 使用相同的列表样式
}