继承

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) {}

// the above block does the same thing as the below block
.a {
  &:extend(.b);
}
.c:extend(.d all) {
  // extends all instances of ".d" e.g. ".x.d" or ".d.x"
}
.c:extend(.d) {
  // extends only instances where the selector will be output as just ".d"
}

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

例子:

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

// the above and the below do the same thing
.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). 扩展必须在最后。

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

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

继承内部规则集

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

在主体内继承:

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

与在每个选择器之后添加扩展完全相同:

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

继承嵌套选择器

Extend 能够匹配嵌套的选择器。 关注 less:

例子:

.bucket {
  tr { // nested ruleset with target selector
    color: blue;
  }
}
.some-class:extend(.bucket tr) {} // nested ruleset is recognized

输出

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

本质上,extend 着眼于编译后的 css,而不是原始的 less。

例子:

.bucket {
  tr & { // nested ruleset with target selector
    color: blue;
  }
}
.some-class:extend(tr .bucket) {} // nested ruleset is recognized

输出

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

精确匹配继承

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

例子:

.a.class,
.class.a,
.class > .a {
  color: blue;
}
.test:extend(.class) {} // this will NOT match the any selectors above

明星确实很重要。 选择器 *.class.class 是等价的,但 extend 不会匹配它们:

*.class {
  color: blue;
}
.noStar:extend(.class) {} // this will NOT match the *.class selector

输出

*.class {
  color: blue;
}

伪类的顺序确实很重要。 选择器 link:hover:visitedlink:visited:hover 匹配同一组元素,但 extend 将它们视为不同的:

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

输出

link:hover:visited {
  color: blue;
}

第 n 个表达式

第 N 种表达形式很重要。 第 N 个表达式 1n+3n+3 是等价的,但扩展不会匹配它们:

: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;
}

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

继承选择器插值

Extend is not 能够匹配选择器和变量。 如果选择器包含变量,extend 将忽略它。

但是,extend 可以附加到插值选择器。

带有变量的选择器将不会被匹配:

@variable: .bucket;
@{variable} { // interpolated selector
  color: blue;
}
.some-class:extend(.bucket) {} // does nothing, no match is found

并在目标选择器中使用变量扩展不匹配:

.bucket {
  color: blue;
}
.some-class:extend(@{variable}) {} // interpolated selector matches nothing
@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) {} // extend inside media
  .selector { // this will be matched - it is in the same media
    color: black;
  }
}
.selector { // ruleset on top of style sheet - extend ignores it
  color: red;
}
@media screen {
  .selector {  // ruleset inside another media - extend ignores it
    color: blue;
  }
}

编译成:

@media print {
  .selector,
  .screenClass { /*  ruleset inside the same media was extended */
    color: black;
  }
}
.selector { /* ruleset on top of style sheet was ignored */
  color: red;
}
@media screen {
  .selector { /* ruleset inside another media was ignored */
    color: blue;
  }
}

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

@media screen {
  .screenClass:extend(.selector) {} // extend inside media
  @media (min-width: 1023px) {
    .selector {  // ruleset inside nested media - extend ignores it
      color: blue;
    }
  }
}

这编译成:

@media screen and (min-width: 1023px) {
  .selector { /* ruleset inside another nested media was ignored */
    color: blue;
  }
}

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

@media screen {
  .selector {  /* ruleset inside nested media - top level extend works */
    color: blue;
  }
  @media (min-width: 1023px) {
    .selector {  /* ruleset inside nested media - top level extend works */
      color: blue;
    }
  }
}

.topLevel:extend(.selector) {} /* top level extend matches everything */

编译成:

@media screen {
  .selector,
  .topLevel { /* ruleset inside media was extended */
    color: blue;
  }
}
@media screen and (min-width: 1023px) {
  .selector,
  .topLevel { /* ruleset inside nested media was extended */
    color: blue;
  }
}

重复检测

目前没有重复检测。

例子:

.alert-info,
.widget {
  /* declarations */
}

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

输出

.alert-info,
.widget,
.alert,
.alert {
  /* declarations */
}

继承的用例

经典用例

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

.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;
}

减少 CSS 大小

Mixins 将所有属性复制到一个选择器中,这会导致不必要的重复。 因此,你可以使用 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;
}

示例(带扩展):

.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;
}

组合样式/更高级的混合

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

例子:

li.list > a {
  // list styles
}
button.list-style {
  &:extend(li.list > a); // use the same list styles
}