本文从http://lesscss.org/features/#extend-feature翻译而来,增加了少量说明。由于英文水平有限,某些地方采用了我所理解的意 思,而不是直译。
扩展
扩展是一个将外层选择符与其引用的选择符进行合并的伪类。
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这个规则的输出:
扩展在输出之前被删除,选择器块保持原样。如果该块中未设置任何属性,则将该块从输出中删除(但扩展仍然可能影响其他选择器)。
这条规则很简单,就是说要扩展另外一个规则的选择器部分,用逗号隔开。也可以认为是,现在的规则想“继承”其他规则的属性。我刚看到时,是有一个疑问的,什么时候要用扩展,为什么会有这种用法,我用mixins不一样能得到同样的功能?先看看输出部分,可以等价于:
nav ul {
color: red;
background: blue;
}
.inline {
color: red;
}
可以看到color: red;这个属性重复了一次。这个例子比较简单,如果.inline属性比较多的话,那么重复的属性也会比较多。可以看出用扩展会让css文件比较小。
另外,如果我们有如下的代码,用扩展可以直接引用,但是却无法使用mixins。
ulclass>liclass{
background-color:blue;
}
//无法直接用mixins,但是可以用extend
.nav-li{
&:extend(ulclass>liclass);
}
我们可以在扩展用例部分看到其他的例子,在此提前说明是为了让您不至于带着太多疑问往下读。
扩展语法
扩展要么附加到选择器,要么放置在规则集中。看起来像是带有选择器参数的伪类,可选择性地在其后增加关键字all
:
例:
.a:extend(.b) {}
// 放置在规则集中也可以
.a {
&:extend(.b);
}
.c:extend(.d all) {
// 将扩展所有和".d" 有关的规则集,例如".x.d" or ".d.x"
}
.c:extend(.d) {
// 只会扩展选择器为".d"的规则集
}
它可以包含一个或多个要扩展的类,以逗号分隔。
例:
.e:extend(.f) {}
.e:extend(.g) {}
// 可以写成如下的形式
.e:extend(.f,.g) {}
扩展附加到选择器
附加到选择器的扩展看起来像一个带有选择器作为参数的普通伪类。一个选择器可以包含多个extend子句,但是所有扩展都必须在选择器的末尾。
- 在选择器之后扩展:
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) {
font-size: 16px;
}
.bag{
color: red;
}
.bucket{
color: blue;
}
输出是
.big-division,
.big-bag,
.big-bucket {
font-size: 16px;
}
.bag,
.big-bag {
color: red;
}
.bucket,
.big-bucket {
color: blue;
}
扩展内部规则集
可以使用&:extend(selector)
语法将扩展放置在规则集的主体中。这是一种简写方式,可替换将其放入该规则集的每个选择器中。
在体内延伸:
pre:hover,
.some-class {
&:extend(div pre);
}
与在每个选择器之后添加扩展名完全相同:
pre:hover:extend(div pre),
.some-class:extend(div pre) {}
扩展嵌套选择器
扩展可以匹配嵌套选择器。如以下less代码:
.bucket {
tr { // 嵌套规则集
color: blue;
}
}
.some-class:extend(.bucket tr) {} // 这种表达式是可以的
输出为
.bucket tr,
.some-class {
color: blue;
}
从本质上讲,扩展将查找编译后的CSS,而不是原始的less文件。
例:
.bucket {
tr & { // 嵌套规则集,但是&放于后面
color: blue;
}
}
.some-class:extend(tr .bucket) {} // 这种写法是正确的
输出为
tr .bucket,
.some-class {
color: blue;
}
扩展的精确匹配
扩展在默认情况下查找完全匹配选择器。在其他情况下,选择器前面是否使用星号意义是一样的,两个不同的nth表达式也可能具有相同含义,但是在扩展时它们必须具有相同的形式才能匹配。唯一的例外是属性选择器中的引号,Less能够推断出它们的含义相同并匹配它们。
例:
.a.class,
.class.a,
.class > .a {
color: blue;
}
.test:extend(.class) {} // 上面三种选择器均不匹配
前置星号不重要,选择器*.class
和.class
是等效的,但扩展时与它们不匹配:
*.class {
color: blue;
}
.noStar:extend(.class) {} // 无法匹配*.class选择器
输出
*.class {
color: blue;
}
伪类的顺序很重要:选择器link:hover:visited
和link:visited:hover
匹配相同的元素集,但Less扩展时将它们视为不同的元素:
link:hover:visited {
color: blue;
}
.selector:extend(link:visited:hover) {}
输出
link:hover:visited {
color: blue;
}
第n个表达式
第N个表达形式很重要。Nth个表达式1n+3
和n+3
是等效的,但extend与它们不匹配:
:nth-child(1n+3) {
color: blue;
}
.child:extend(:nth-child(n+3)) {} //与1n+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关键字时,它告诉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 { // 媒体查询中的嵌套规则,实际与上面的extend不在同一个媒体查询中,被忽略
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 {//.alert有重复
/* 声明 */
}
扩展用例
经典用例
经典的用例是避免添加基类。例如,如果您有
.animal {
background-color: black;
color: white;
}
并且您想要一个animal的子类型来覆写背景色,那么您有两个选择,首先是更改HTML,添加一个bear类
<a class="animal bear">Bear</a>
.animal {
background-color: black;
color: white;
}
.bear {
background-color: brown;
}
或者您使用扩展,会有更加简单的html代码,只使用bear类。例如
<a class="bear">Bear</a>
.animal {
background-color: black;
color: white;
}
.bear {
&:extend(.animal);
background-color: brown;
}
减少CSS大小
Mixins将所有属性复制到选择器中,这可能导致不必要的重复。因此您可以使用扩展而不是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;
}
组合样式/更高级的mixin
另一个用例是mixin的替代方案,因为mixin只能与简单的选择器一起使用。如果您有两个不同的html块,但需要对两者使用相同的样式,则可以使用扩展来关联两个区域。
例:
li.list > a {
// list styles
}
button.list-style {
&:extend(li.list > a); // 使用相同的list styles
}