购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

2.2 详解 @layer 规则

接下来介绍非常实用的 @layer 规则。

2.2.1 @layer 规则解决的问题

先讲解一下设计 @layer 的初衷。

我们在实际开发的时候,经常会使用第三方组件。每个产品通常都有自己的UI样式风格,当引入第三方组件的时候,往往需要对这些组件的UI进行重置,例如换肤、变色等。此时,我们的做法是使用优先级更高的选择器进行覆盖,例如第三方组件中某个按钮的选择器是:

.container .some-button { height: 30px; }

当需要重置的时候,可能就会使用类似于下面的选择器,通过增加选择器复杂度的方式进行重置。

.reset .container .some-button { height: 40px; }

这就会使我们的CSS代码变得很臃肿,维护成本上升,同时过于复杂的选择器也使CSS渲染的性能不是很好。

又如这个困扰我很久的例子,对于链接元素的CSS reset ,有一种非常好的方法是使用 :any-link 伪类,代码示意如下:

:any-link { color: darkblue; }
:any-link:hover { color: blue; }

其语义明确,匹配精准,且无须担心 :visited 伪类的干扰,可以参见10.2节讲解的超链接伪类。

然而,这个伪类却很少有人使用,其原因只有一个,那就是伪类的优先级比较高,不太适合作为CSS reset 使用,因为一旦设置这个伪类,某个 <a> 元素按钮想要被重置颜色,所需的选择器成本就会很高,提升了整个项目的选择器复杂度。

而有了 @layer 规则,上面这些问题就迎刃而解了。我们只要将希望获得低优先级的CSS代码放在 @layer 规则中,就无须再担心选择器优先级过高的问题,因为 @layer 规则的级联层级比常规的CSS代码的级联层级低。

参见这里的CSS代码示意:

@layer {
  .container .some-button { height: 30px; }
  :any-link { color: darkblue; }
  :any-link:hover { color: blue; }
}
/* 业务代码 */
.some-button { height: 40px; }
a { color: deepskyblue; }

此时相关的CSS代码在浏览器的优先级层级关系如图2-5和图2-6所示。

图2-5 按钮的单类名优先级更高

图2-6 <a> 元素优先级高于 :any-link 伪类

从图2-5可以看出,虽然业务代码中的按钮选择器只有一个类名 .some-button ,其优先级低于 .container .some-button 这两个类名,但是由于代码所在的级联层级更高,因此,还是重置了 30px

从图2-6可以看出,链接的颜色最终按照 a 标签选择器渲染了,再也不用担心 :any-link 伪类作为CSS reset 代码会影响业务代码中 <a> 元素的样式设置了。

眼见为实,读者可以输入https://demo.cssworld.cn/selector2/2/2-1.php或者扫描下面的二维码查看对应的效果。

IMG_256

这就是 @layer 规则的作用,可以让CSS代码的级联层级降低,从而确保主业务的CSS代码不受第三方组件的CSS代码的影响。

2.2.2 掌握 @layer 规则的语法

@layer 这个AT规则(CSS at-rule)的语法如下:

@layer {rules}
@layer layer-name {rules};
@layer layer-name;
@layer layer-name, layer-name, layer-name;

其中, @layer {rules} 语法在前文出现过,没有任何层级名,称为匿名级联层,而下面3种语法均需要自定义级联层的名称,称为命名级联层。

下面重点介绍这3种命名级联层语法。

1.命名带规则语法

这种语法和匿名级联层语法的唯一区别就是多了一个名称,便于开发人员识别与管理,从性质上来讲,有点类似于编程语言中的变量。

例如:

@layer button {
  .container .some-button { 
    height: 30px;
  }
}
@layer link {
  :any-link {
    color: blue;
  }
}

此时,我们可以使用下面的单命名语法或者多命名语法来灵活调整不同级联层的优先级顺序。如果我们没有这样的需求,则可以直接使用匿名级联层语法。

2.单命名语法

@layer layer-name 主要用于灵活设置 @layer 规则之间的优先级顺序。例如,有一个级联层,名为 peacock ,希望这个级联层的优先级最低,但是,相关CSS代码的位置却无法控制,有可能靠前,也可能靠后,此时, @layer layer-name 这个语法就有用武之地了。

@layer peacock;
 
/* ……大量的CSS代码…… */
/* ……大量的CSS代码…… */
/* ……大量的CSS代码…… */
 
/* 虽然我位置靠后,但我优先级最低 */
@layer peacock {
  .bottom-layer {
      content: 'hello world'
  }
}

上面这段CSS代码,虽然 @layer peacock{} 出现在CSS语句的最后面,但是由于在开头设置了 @layer peacock; 这行代码, peacock 这个级联层中的所有CSS代码的优先级都是最低的。

3.多命名语法

@layer layer-name, layer-name, layer-name 这个多命名语法和 @layer layer-name 这个单命名语法的作用是类似的,也是用来灵活调整 @layer 规则的整体优先级的。

在默认情况下, @layer 规则内CSS声明的优先级取决于先后顺序,例如:

@layer b1 {
  button { padding: 10px; }
}
@layer b2 {
  button { padding: 20px; }
}

此时,如果页面中有一个 <button> 按钮元素,则此按钮元素的内间距是 20px ,因为设置 padding:20px 的规则出现在后面。

如果我们希望 b2 级联层的优先级高于 b1 级联层的优先级,则使用多命名语法设置好先后顺序就可以了。

@layer b2, b1;
@layer b1 {
  button { padding: 10px; }
}
@layer b2 {
  button { padding: 20px; }
}

此时,按钮元素匹配的 padding 内间距值是 10px ,因为 @layer 多命名语法中 b1 出现在后面,优先级更高,参见图2-7所示的优先级覆盖效果。

layer-multiple-name

图2-7 多命名级联层语法的作用示意

眼见为实,读者可以输入https://demo.cssworld.cn/selector2/2/2-2.php或者扫描下面的二维码查看对应的效果。

IMG_256

2.2.3 使整个CSS变成 @layer

对于第三方的CSS文件,尤其是那些通过CDN实现的绝对地址CSS,我们是没办法修改相关的代码的,此时有办法使这部分CSS变成低优先级的级联层吗?答案是可以的,我们可以尝试使用 @import 语法。

如果希望导入其他CSS文件的低优先级,可以这样设置:

@import './example.css' layer(example);

也就是在传统的 @import 语法后面再添加一个 layer(some-name) 就可以了。

此时, example.css 中的所有CSS声明的优先级都低于常规设置的CSS声明。其中 layer() 函数中的名称可以自行定义,如果想要调整 layer(some-name) 的优先级,可以参照多命名语法的用法。例如:

layer button, example;
@import './example.css' layer(example);
@layer button {}

同时也支持匿名引入的语法,例如:

@import './example.css' layer;

2.2.4 @layer 规则的嵌套

@layer 规则还支持更加复杂的嵌套语法。先看一个比较简单的嵌套例子:

@layer outer {
    button {
        width: 100px;
        height: 30px;    
    }
    @layer inner {
        button {
            height: 40px;
            width: 160px;
        }    
    }
}

此时, button 选择器的外层优先级高于内层。读者可以这么理解:每多一层 @layer ,样式的优先级就降低一层。因此,上面的代码中最终生效的是外层的 width:100px height:30px ,效果如图2-8所示。

图2-8 @layer 规则嵌套语法的优先级渲染效果

此时在开发者工具的样式面板中可以看到图2-9所示的CSS代码优先级覆盖关系。

layer-nest-1

图2-9 @layer 规则嵌套语法的优先级覆盖示意

眼见为实,读者可以输入https://demo.cssworld.cn/selector2/2/2-3.php或者扫描下面的二维码查看对应的效果。

IMG_256

1.点( . )级联写法

内外嵌套的语法还可以使用字符点(.)进行连接,例如,上面例子中的CSS代码和下面的CSS代码的效果是完全一样的,参见图2-8。

@layer outer {
  button {
    width: 100px;
    height: 30px;    
  }
}
@layer outer.inner {
  button {
    height: 40px;
    width: 160px;
  }    
}

嵌套的层数不限,例如嵌套5层、10层甚至更多层都是可以的,当然,实际开发中不会用到这样深的层级关系。

2.多嵌套语法下的优先级

当存在多个 @layer 规则,同时这些 @layer 规则之间都有嵌套关系的时候,各个CSS声明的优先级又是怎样的呢?只需要记住这样一句话:内层 @layer 规则的优先级由外层 @layer 规则决定。例如下面这个例子:

@layer 甲 {
  p { color: red; }
  @layer 乙 {
    p { color: green; }
  }
}
@layer 丙 {
  p { color: orange; }
  @layer 丁 {
    p { color: blue; }
  }
}

由于“丙”位置靠后,因此“丙”的优先级高于“甲”,而对于单独某个级联层的优先级,则是外层的优先级更高,因此,最终的优先级顺序是:丙 > 丙.丁 > 甲 > 甲.乙

真实渲染的覆盖关系如图2-10所示:

图2-10 @layer 规则在多嵌套语法下的优先级覆盖示意

因此,最终 <p> 元素应用的 color 属性值是 orange

眼见为实,读者可以输入https://demo.cssworld.cn/selector2/2/2-3.php或者扫描下面的二维码查看对应的效果。 Vs8beOGTAY8nBcG57iQ5qSTlMXKNCDnzNomN7R9dgQQ5U3iZHoPQWzFZEfq1H1V+

IMG_256
点击中间区域
呼出菜单
上一章
目录
下一章
×