文章目录
1. 概述
Extend 是一个 Less 伪类,实现对当前层级规则的扩展。
nav ul {
&:extend(.inline);
background: blue;
}
在上面的规则集中,:extend
选择器会将 .inline
的规则应用到”扩展选择器”即 nav ul
上。同时, nav ul
本身的规则会保持原样。
如下所示:
nav ul {
&:extend(.inline);
background: blue;
}
.inline {
color: red;
}
生成的结果如下:
nav ul {
background: blue;
}
.inline,
nav ul {
color: red;
}
2. 语法
extend
看起来像一个伪类,可以直接附加到选择器上,也可以在规则集中使用,还支持一个可选的关键字 all
。
示例如下:
// 方式 1:直接附加在选择器上
.a:extend(.b) {
color: red;
}
// 方式 2:在规则集中使用
.a {
&:extend(.b);
color: red;
}
// 上面两种方式效果完全一致
关键字 all
的使用
.c:extend(.d all) {
// 扩展 `.d` 的所有相关选择器,例如 `.x.d` 或 `.d.x`
color: red;
}
.c:extend(.d) {
// 仅扩展选择器 `.d`
color: red;
}
当然,它也可以包含一个或多个要扩展的类,用逗号分隔,示例如下:
.e:extend(.f) {
color: red;
}
.e:extend(.g) {
color: red;
}
// 和上面两个得到的结果完全一致
.e:extend(.f, .g) {
color: red;
}
3. 附加到选择器上
附加到选择器的 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)
如果规则集包含多个选择器,则其中任何一个都可以扩展,示例如下:
// 附加到选择器
.bag {
border: 1px solid;
}
.bucket {
margin: 10px;
}
.show {
display: block;
}
.big-division:extend(.bag),
.big-bag:extend(.bag, .show),
.big-bucket:extend(.bucket):extend(.show) {
color: red;
}
生成的结果如下:
.bag,
.big-division,
.big-bag {
border: 1px solid;
}
.bucket,
.big-bucket {
margin: 10px;
}
.show,
.big-bag,
.big-bucket {
display: block;
}
.big-division,
.big-bag,
.big-bucket {
color: red;
}
4. 在规则集中使用
除了附在在选择器后面,还可以直接在规则集中使用,父选择器也是支持的,如:&:extend(selector)
,而且,放入规则集后,这个规则集对应的所有选择器都将被扩展(一种快捷方式)。
.ru {
top: 10;
}
pre:hover,
.some-class {
&:extend(.ru);
left: 20;
}
// 和上面写法完全一致
pre:hover:extend(.ru),
.some-class:extend(.ru) {
left: 20;
}
生成的结果如下:
.ru,
pre:hover,
.some-class {
top: 10;
}
pre:hover,
.some-class {
left: 20;
}
5. 扩展嵌套选择器
Extend能够匹配嵌套选择器。以下更少:
.bucket {
tr { // 嵌套的选择器
color: blue;
}
}
.some-class:extend(.bucket tr) {
border: 1px;
}
生成的结果如下:
.bucket tr,
.some-class {
color: blue;
}
.some-class {
border: 1px;
}
而且,扩展最终使用的是 css,而不是原来的 less。
.bucket {
tr & {
color: blue;
}
}
.some-class:extend(tr .bucket) {
border: 1px;
}
生成的结果如下:
tr .bucket,
.some-class {
color: blue;
}
.some-class {
border: 1px;
}
6. 精确匹配
在默认情况下,:extend(selector)
会去精确匹配选择器,也就是需要完全相同才会匹配。
.a.class,
.class.a,
.class > .a {
color: blue;
}
.test {
border: 1px;
}
虽然在选择器中,*.class
和 .class
相等,但是 extend
不会匹配:
*.class {
color: blue;
}
// 匹配不到任何选择器
.noStar:extend(.class) {
border: 1px;
}
伪类的顺序也很重要。选择器 link:hover:visited
和 link:visited:hover
的确是匹配同一组元素,但extend
不会匹配上:
link:hover:visited {
color: blue;
}
// 匹配不到任何选择器
.selector:extend(link:visited:hover) {
border: 1px;
}
7. nth
表达式
在选择器中,表达式 1n+3
和 n+3
是等效的,但 extend
却不会匹配到它们:
:nth-child(1n+3) {
color: blue;
}
// 匹配不到任何选择器
.child:extend(:nth-child(n+3)) {}
8. 属性选择器
有意思的是,属性选择器中的引号类型是无关紧要的
[title='identifier'] {
color: blue;
}
[title='identifier'] {
color: blue;
}
[title='identifier'] {
color: blue;
}
.noQuote:extend([title='identifier']) {
border: 1px;
}
.singleQuote:extend([title='identifier']) {
border: 1px;
}
.doubleQuote:extend([title='identifier']) {
border: 1px;
}
生成的结果如下:
[title='identifier'],
.noQuote,
.singleQuote,
.doubleQuote {
color: blue;
}
[title='identifier'],
.noQuote,
.singleQuote,
.doubleQuote {
color: blue;
}
[title='identifier'],
.noQuote,
.singleQuote,
.doubleQuote {
color: blue;
}
.noQuote {
border: 1px;
}
.singleQuote {
border: 1px;
}
.doubleQuote {
border: 1px;
}
9. all
关键词
当在扩展参数后指定 all
关键字时,意味着告诉 Less 将该选择器作为另一个选择器的一部分进行匹配。匹配到的部分会进行替换,从而生成一个新的选择器。示例如下:
a.b.test,
.test.c {
color: orange;
}
.test {
&:hover {
color: green;
}
}
.replacement:extend(.test all) {
border: 1px;
}
生成的结果如下:
a.b.test,
.test.c,
a.b.replacement,
.replacement.c {
color: orange;
}
.test:hover,
.replacement:hover {
color: green;
}
.replacement {
border: 1px;
}
10. 变量
extend
不会和任何变量进行匹配,若选择器包含变量,会直接忽略。
@variable: .bucket;
@{variable} {
color: blue;
}
// 匹配不到任何选择器
.some-class:extend(.bucket) {
border: 1px;
}
.bucket {
color: blue;
}
@variable: .bucket;
// 匹配不到任何选择器
.some-class:extend(@{variable}) {
border: 1px;
}
官网指出:选择器使用变量时,是可以正常匹配的。但是我实验过后,发现是不能的,这里留待考究。
11. @media
中使用 :extend
@media
中的 :extend
仅匹配当前 @media
中的选择器。
@media print {
// 成功匹配
.screenClass:extend(.selector) {
left: 1;
}
// 同一个 media 中的选择器,匹配
.selector {
color: black;
}
}
// 规则集在顶层,内层 extend 会忽略
.selector {
color: red;
}
@media screen {
// 规则集在另一 media 中,仅会被当前 media 中的 extend 匹配
.selector {
color: blue;
}
}
生成的结果如下:
@media print {
.screenClass {
left: 1;
}
.selector,
.screenClass {
color: black;
}
}
.selector {
color: red;
}
@media screen {
.selector {
color: blue;
}
}
注意,同一个 @media
中嵌套的 @media
内的选择器也不会匹配
@media screen {
// 匹配不到任何选择器
.screenClass:extend(.selector) {
left: 1;
}
@media (min-width: 1023px) {
// 选择器在嵌套的 media 中,无法匹配
.selector {
color: blue;
}
}
}
顶层的 extend 会去匹配所有层级的选择器
@media screen {
.selector-t {
color: blue;
}
@media (min-width: 1023px) {
.selector-t {
color: blue;
}
}
}
// 顶层的 extend 会去匹配所有层级的选择器
.topLevel:extend(.selector-t) {
left: 1;
}
生成的结果如下:
@media screen {
.selector-t,
.topLevel {
color: blue;
}
}
@media screen and (min-width: 1023px) {
.selector-t,
.topLevel {
color: blue;
}
}
.topLevel {
left: 1;
}
12. 重复检测
目前没有做重复检测如下:
.alert-info,
.widget {
left: 1;
}
.alert:extend(.alert-info, .widget) {
top: 2;
}
生成的结果如下:
.alert-info,
.widget,
.alert,
.alert {
left: 1;
}
.alert {
top: 2;
}
13. 使用示例
13.1 经典用例
典型的用例是避免重复写规则集。
比如:
.animal {
background-color: black;
color: white;
}
如果期望覆盖 animal
的背景色,有两种方式:
第一种:改变 HTML,写两个类
<a class="animal bear">熊</a>
.animal {
background-color: black;
color: white;
}
.bear {
background-color: brown;
}
第二种:使用 extend
<a class="bear">熊</a>
.animal {
background-color: black;
color: white;
}
.bear {
&:extend(.animal);
background-color: brown;
}
13.2 减小 CSS 体积
使用 mixins 非常方便,但 mixins 会将所有属性都复制到选择器中,这可能会导致不必要的重复。
因此,可以使用 extends
来替换 mixin 将选择器移动到希望使用的属性上,从而减少生成的 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;
}
13.3 样式组合
一个更高级的用法是,当选择器比较复杂时(此时 mixin 已经无法实现了,因为 mixin 只能和简单的选择器使用),又需要对规则集进行复用,那么便可以使用 extends
。
li.list > a {
line-height: 20px;
}
button.list-style {
&:extend(li.list > a);
}
生成的结果如下:
li.list > a,
button.list-style {
line-height: 20px;
}