CSS 优先权
CSS 层叠(级联)
当多个 css 规则同时运用在一个元素上时,会产生样式表的 层叠 (Cascade),这是一个合并冲突样式的过程,如何判断哪个样式规则生效呢?主要从以下几个方面判断:
判断顺序:从上到下,上一级一样则判断下一级,直到某一个规则优先级胜出
- 重要程度:属性值后有 !important ,属性优先级最高
- 样式来源
- 层叠层
- 选择器优先级
- 出现顺序:后面的规则会覆盖前面的规则
样式来源
CSS 可根据来源分为 3 种类型:用户代理样式表(浏览器默认的)、用户样式表(用户写的)、作者样式表(开发人员写的)
用户样式表有什么用?假如用户有视力障碍,需要将文字放大 200%,这时候可以通过设置用户样式表覆盖原有的 CSS
优先级 由低到高 如下:
- 用户代理样式表中的声明(例如,浏览器的默认样式,在没有设置其他样式时使用)
- 用户样式表中的常规声明(由用户设置的自定义样式)
- 作者样式表中的常规声明(这些是我们 web 开发人员设置的样式)
- 正在动画的样式
- 作者样式表中的 !important 声明
- 用户样式表中的 !important 声明
- 用户代理样式表中的 !important 声明
- 正在过渡的样式
为什么 !important 的优先级相反?为了保证用户样式表能够有足够的优先级去覆盖其他样式表
层叠层(级联层)
创建层叠层
@layer 声明方式
使用 @layer 声明规则,这将创建一个或多个没有分配任何样式的具名层
@layer theme,layout,utilities;
- 越靠后声明的层优先级越高
- 通常,你需要在 CSS 的第一行声明这个 @layer,以便完全控制层的顺序。
- 如果上述声明是站点 CSS 的第一行,那么层的顺序将是 theme、layout 和 utilities。
- 如果在上述语句之前已经创建了一些层,例如,如果 layout 已经存在,只会创建 theme 和 utilities,层顺序将是 layout、theme 和 utilities
@layer 块方式
可以使用块 @layer 来创建匿名层或具名层
/* 创建第一个层:具名层 `layout` */
@layer layout {
main {
display: grid;
}
}
/* 创建第二个层:匿名层 */
@layer {
body {
margin: 0;
}
}
- 越靠后创建的层优先级越高
- 没有办法重新排序已声明的层。如果在创建层之后,使用 @layout 声明,并且声明的是已经创建的层,声明将无法改变优先级顺序,仍然是 @layout 块的创建顺序决定优先级顺序
- 未命名的层,没有办法引用它们或向它们添加额外的样式
- 在层之外声明的所有样式都会加入到一个隐含的层中,这个隐含层会被排到声明列表的最后面,即拥有最高的优先级
关于层创建与媒体或特性查询
如果你使用媒体或特性查询来定义层,且媒体不匹配或特征不被支持,则不会创建该层(这有些反直觉,通常哪怕没有声明,使用 @layout 块仍可创建层)
/* 表示最小宽度不小于 50em 时创建 site 层,否则不建立 site 层 */
@media (min-width: 50em) {
@layer site;
}
@layer page {
h1 {
text-decoration: overline;
color: red;
}
}
@layer site {
h1 {
text-decoration: underline;
color: green;
}
}
使用 @import 将样式表导入层
导入时,@import 语句必须出现在 <style> 代码块的最前面
以下层分别将样式表导入 components 层、components 层中的嵌套 dialog 层和一个未命名层
@import url("components-lib.css") layer(components);
@import url("dialog.css") layer(components.dialog);
@import url("marketing.css") layer();
将多个 CSS 文件导入到单个层中
@import url(comments.css) layer(social);
@import url(sm-icons.css) layer(social);
使用媒体查询和特性查询根据特定条件导入样式并创建层,以下将样式表导入到 international 层,但前提是浏览器支持 display: ruby,而且被导入的文件取决于屏幕的宽度
@import url("ruby-narrow.css") layer(international) supports(display: ruby) and
(width < 32rem);
@import url("ruby-wide.css") layer(international) supports(display: ruby) and
(width >= 32rem);
嵌套层
嵌套层是具名层或匿名层中的子层。每个层叠层(即使是匿名的)都可以包含嵌套层。导入到另一个层中的层会成为该层中的嵌套层。
创建嵌套层
嵌套层和普通层叠层一样,也可以通过三种方式创建:声明、块、@import,只不过声明、@import 用点表示法( dad-layer.son-layer )表示嵌套关系,块使用块中嵌套块的方式表示
@import url("components-lib.css") layer(components);
@import url("narrowtheme.css") layer(components.narrow);
- 在第一行中,我们将 components-lib.css 导入 components 层。如果该文件包含任何层,无论命名与否,这些层都会成为 components 层中的嵌套层。
- 第二行将 narrowtheme.css 导入 narrow 层,narrow 是 components 的子层。嵌套的 components.narrow 会作为 components 层中的最后一个层创建,除非 components-lib.css 已经包含一个 narrow 层,在这种情况下,narrowtheme.css 的内容会被附加到 components.narrow 嵌套层。
/* 向 components.narrow 嵌套层添加样式 */
@layer components.narrow {
main {
width: 50vw;
}
}
如何确定优先权
常规层叠层的优先权顺序
@import url(A.css) layer(firstLayer);
@import url(B.css) layer(secondLayer);
@import url(C.css);
上面的例子优先权如下(从低到高):
- firstLayer 普通样式(A.css)
- secondLayer 普通样式(B.css)
- 未分层普通样式(C.css)
- 内联普通样式
- 动画样式
- 未分层重要样式(C.css)
- secondLayer 重要样式(B.css)
- firstLayer 重要样式(A.css)
- 内联重要样式
- 过渡样式
如果样式有冲突,后面的样式会覆盖前面的样式
嵌套层叠层的优先权顺序
- 非嵌套样式优先于普通嵌套样式
- 晚创建或声明的嵌套层样式优先于先创建的
- 对于重要样式,前面规则的优先级反转
选择器优先级
- 基本思想:选择器越具体,css 优先级越高
- 巧妙利用优先级,通过样式的覆盖,可以减少代码量
- 浏览器如何计算优先级呢?计算方法:ID-类(属性选择器、伪类选择器)-元素(伪元素),分别对应,百位-十位-个位
/* 有0个ID选择器,有2个类选择器,有2个元素选择器,因此优先级为 0-2-2 */
li > a[href*="en-US"] > .inline-warning{
...
}
- 如何比较优先级?先比较 ID,ID 如果一样则比较类,类如果一样则比较标签
- 特殊伪类的优先级::where() 的优先级永远为 0,:is() :not() 的优先级由括号中优先级最高的选择器决定
- 通用选择器(*)、组合符(+、>、~、' ')优先级都为 0