Less 继承

在 Less v1.4.0 引入了 Extend,Extend 是一个 Less 伪类,它将放置它的选择器与其引用的匹配的选择器合并。例如:

// 放置 extend 的选择器,nav ul
nav ul {
   // 引用 .inline
   &:extend(.inline);
   background: blue;
}

在上面的规则集中,:extend 选择器会将 "继承选择器" (nav ul) 应用于 .inline 类,无论 .inline 类出现在哪里。声明块将保持原样,但不会引用扩展(因为扩展不是 CSS)。所以如下:

nav ul {
   // 表示继承 .inline 下声明的样式
   &:extend(.inline);
   background: blue;
}

.inline {
   color: red;
}

编译 Less,输出 CSS 如下:

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

继承语法

扩展要么附加到选择器,要么放入规则集中。它看起来像一个带有选择器参数的伪类,可选地后跟关键字 all。例子:

/* 继承 .b1 */
.b1 {
   color: red;
}
.a1:extend(.b1) {
   background: blue;
}

/* 继承 .b2 */
.b2 {
   color: red;
}
.a2 {
   &:extend(.b2);
   background: blue;
}

/* 扩展 “.b3” 的所有实例,例如 “.x.b3” 或 “.b3.x” */
.b3 {
   color: red;
   .myDiv {
       border: solid 1px red;
   }
}
.div3 {
   .b3 {
       font-size: 20px;
   }
}

.a3:extend(.b3 all) {
   background: blue;
}

/* 仅扩展 “.b4” 选择器,仅输出 “.b4” 的实例 */
.b4 {
   color: red;
   .myDiv {
       border: solid 1px red;
   }
}
.div4 {
   .b4 {
       font-size: 20px;
   }
}
.a4:extend(.b4) {
   background: blue;
}

编译 Less,输出 CSS 如下:

/* 继承 .b1 */
.b1,
.a1 {
 color: red;
}
.a1 {
 background: blue;
}

/* 继承 .b2 */
.b2,
.a2 {
 color: red;
}
.a2 {
 background: blue;
}

/* 扩展 “.b3” 的所有实例,例如 “.x.b3” 或 “.b3.x” */
.b3,
.a3 {
 color: red;
}
.b3 .myDiv,
.a3 .myDiv {
 border: solid 1px red;
}
.div3 .b3,
.div3 .a3 {
 font-size: 20px;
}
.a3 {
 background: blue;
}

/* 仅扩展 “.b4” 选择器,仅输出 “.b4” 的实例 */
.b4,
.a4 {
 color: red;
}
.b4 .myDiv {
 border: solid 1px red;
}
.div4 .b4 {
 font-size: 20px;
}
.a4 {
 background: blue;
}

注意,extend 可以包含一个或多个要扩展的类,以逗号分隔。例子:

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

extend 附加到选择器

到选择器的 extend 看起来更像一个普通的伪类,将选择器作为参数。一个选择器可以包含多个 extend 子句,但所有 extend 都必须位于选择器的末尾。其中:

  • extend 必须放在选择器之后,例如:pre:hover:extend(div pre),如果将 extend 没有放在选择器末尾,是不允许的,例如:pre:hover:extend(div pre).nth-child(odd).

  • 选择器和 extend 之间的空格是允许的,例如:pre:hover :extend(div pre)

  • 选择器允许多个 extend,例如:pre:hover:extend(div pre):extend(.bucket tr) 等价 pre:hover:extend(div pre, .bucket tr)

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

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

extend 内部规则集

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

在主体内放置 extend:

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

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

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

extend 嵌套选择器

Extend 能够匹配嵌套的选择器。例子:

.bucket {
   tr {
       // 具有选择器的嵌套规则集        
       color: blue;
   }
}

// 继承嵌套规则集
.some-class:extend(.bucket tr) {
   //...
}

编译 Less,输出 CSS 如下:

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

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

.bucket {
   // 这里的 & 表示 .bucket
   tr & {
       // 嵌套规则集
       color: blue;
   }
}

// 继承嵌套规则集
.some-class:extend(tr .bucket) {
   //...
}

编译 Less,输出 CSS 如下:

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

精确匹配 extend

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

例子:

.a.class,
.class.a,
.class > .a {
   color: blue;
}

// 这将与上面的任何选择器不匹配
.test:extend(.class) {
   //...
}

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

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

编译 Less,输出 CSS 如下:

*.class {
   color: blue;
}

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

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

编译 Less,输出 CSS 如下:

link:hover:visited {
   color: blue;
}

第 n 个表达式

第 n 个表达式形式确实很重要。第 n 个表达式 1n+3 和 n+3 是等价的,但 extend 不会匹配它们:

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

:nth-child(n+3) {
   background: red;
}

.child:extend(:nth-child(n+3)) {
   font-size: 12px;
}

编译 Less,输出 CSS 如下:

:nth-child(1n+3) {
 color: blue;
}
:nth-child(n+3),
.child {
 background: red;
}
.child {
 font-size: 12px;
}

属性选择器中的引用类型无关紧要。以下所有内容都是等价的:

[title=identifier] {
 color: blue;
}

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

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

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

编译 Less,输出 CSS 如下:

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

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

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

Extend “all”

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

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

.replacement:extend(.test all) {}

编译 Less,输出 CSS 如下:

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

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

extend 选择器插值

Extend 无法将选择器与变量匹配。若选择器包含变量,则 extend 将忽略它。但是,extend 可以附加到插值选择器。

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

@variable: .bucket;
@{variable} { // 插值选择器
 color: blue;
}
.some-class:extend(.bucket) {} // 什么也不做,找不到匹配项

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

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

编译以上两个 Less,输出 CSS 如下:

.bucket {
 color: blue;
}

但是,附加到插值选择器的 :extend 有效:

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

编译 Less,输出 CSS 如下:

.bucket, .selector {
 color: blue;
}

作用域/继承内部 @media

目前,@media 声明中的 :extend 只会匹配同一媒体声明中的选择器:

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

编译 Less,输出 CSS 如下:

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

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

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

编译 Less,输出 CSS 如下:

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

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

@media screen {
 .selector {  /* 嵌套 media 中的规则集 - 顶级扩展工作 */
      color: blue;
 }
 @media (min-width: 1023px) {
   .selector {  /* 嵌套 media 中的规则集 - 顶级 extend 工作 */
       color: blue;
   }
 }
}

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

编译 Less,输出 CSS 如下:

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

重复检测

目前没有重复检测。例子:

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

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

编译 Less,输出 CSS 如下:

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

编译 Less,输出 CSS 如下:

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

编译 Less,输出 CSS 如下:

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

组合样式/更高级的混合

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

例子:

li.list > a {
    // list 样式
}
button.list-style {
    &:extend(li.list > a); // 使用相同的列表样式
}
说说我的看法
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
公众号