前言
层叠样式表 CSS 作为 Web 重要组成部分,开发人员的关注点大多在于复杂的视觉效果、惆怅的浏览器兼容性、脆弱的可维护性,而对于最基本的层叠优先级规则,往往如同雾里看花,人云亦云,甚至产生原则性谬误,本文基于规范文档,尝试理清脉络。
层叠样式
所谓层叠,跳过晦涩定义,简单理解为,浏览器为特定元素,不同来源的属性声明,选择优先级最高的终值。
优先级排序依次如下:
Origin and Importance
规则声明来源(Origin)分为以下部分:
user agent declarations- 浏览器预设样式user declarations- 用户手动预设样式,部分浏览器不支持author declarations- 开发人员设定样式Animation- 动画插帧Transition- 过渡效果插帧
Importance 暨使用关键字 !important 声明规则。
优先级排序如下:
Transition declarationsImportant user agent declarationsImportant user declarationsImportant author declarationsAnimation declarationsNormal author declarationsNormal user declarationsNormal user agent declarations
一般情况下,仅考虑浏览器预设样式,开发者设定样式即可,终端用户样式不纳入考虑。
Scope
通过 scoped style element 声明的样式,仅对其父元素范围内生效。如果存在嵌套关系,优先级顺序如下:
Important ansestor declarationsImportant descendant declarationsNormal descendant declarationsNormal ansestor declarations
unscoped declarations 可以理解作用域为 root element,style attribute declarations 可以理解作用域为元素本身,style attribute important declarations 理解作用域为 root element。
<div class="outer">
<style scoped>
.success {
color: purple;
}
</style>
<ul class="base">
<li class="success">success</li>
<li class="success">success</li>
<li class="success">success</li>
</ul>
<div class="inner">
<style scoped>
.success {
color: yellow;
}
</style>
<ul class="base">
<li class="success">success</li>
<li class="success">success</li>
<li class="success">success</li>
</ul>
</div>
</div>
示例代码 .success 大概率全部为黄色,因为规范已删除 scoped css,大部分浏览器已不支持。顺便一提,通过工程化手段能够实现类似的功能。
原始代码:
<style scoped>
.example {
color: red;
}
</style>
<template>
<div class="example">hi</div>
</template>
转换后代码:
<style>
.example[data-v-f3f3eg9] {
color: red;
}
</style>
<template>
<div class="example" data-v-f3f3eg9>hi</div>
</template>
Specificity
选择器的特异性由选择器本身的成分确定,计算规则如下:
- 计数选择器中
ID选择器数量 A - 计数选择器中类选择器、属性选择器、伪类选择器数量 B
- 计数选择器中元素原则器、伪元素选择器数量 C
选择器特异性标记记为:
比较时,按从左至右方向比较。
特殊场景需要特别注意:
- 伪类选择器
:is()、:not()、:has()特异性为参数选择器列表中,特异性最高的选择器特异性 - 伪类选择器
:nth-child(An+B [of S]?)、:nth-last-child(An+B [of S]?)特异性为参数选择器列表中,特异性最高的选择器特异性叠加普通伪类选择器特异性 - 伪类选择器
:where()特异性为0 - 通配选择器
*特异性为0
举例说明:
| 选择器 | 特异性 |
|---|---|
| #container .header | (1, 1, 0) |
| #container section | (1, 0, 1) |
| .container *:not(.header) | (0, 2, 0) |
Order of Appearance
位置靠后的样式声明优先级更高,包含两点:
- 单文件内样式声明顺序
- 多文件
@import(),<style>,<link>引入先后顺序
扩展思考
理论基本介绍完毕,将理论应用于实践才是最终目的。
四参数比较法
选择器优先级,可能看到的四参数版本:
- 行内样式声明标志位计为 A
- 计数选择器中 ID 选择器数量 B
- 计数选择器中类选择器、属性选择器、伪类选择器数量 C
- 计数选择器中元素原则器、伪元素选择器数量 D
比较时,按从左至右方向比较:
延伸出加权取和比较法:
问题:如何看待这种比较方式
自动填充
部分浏览器支持表单自动填充,默认情况下,填充后的输入框样式较为丑陋,且与整体风格不搭,默认的效果基本如下(图来自网络):
Chrome 78 样式声明如下:
input:-internal-autofill-selected {
background-color: rgb(232, 240, 254) !important;
background-image: none !important;
color: rgb(0, 0, 0) !important;
}
Safari 13 样式声明如下:
input:-webkit-autofill,
input:-webkit-autofill-strong-password {
background-color: rgb(250, 255, 189);
background-image: none;
color: rgb(0, 0, 0);
}
问题:如何处理浏览器预设丑不拉几的自动填充效果?
其它
- 如何覆盖依赖库引入的样式?
- 如何避免复杂的优先级计算?
- 如何在多人协作项目中维护样式?