从webkit内核简单看css样式和css规则优先级(权重)
webkit中样式相关类及类间关系
资料来源: 《webkit技术内幕》
结构相关类:
1.StyleRuleBase类: 单个的样式规则(选择器+规则体)
2.StyleSheetContents类: 样式规则集,其成员-m_childRules是一个StyleRuleBase实例的列表,是1:n的数量关系
3.CSSStyleSheet类: 成员-m_contents是一个StyleSheetContents实例,是1:1的数量关系
4.DocumentStyleSheetCollection类: 多种来源的CSSStyleSheet实例(用户样式表,网页作者样式表,默认样式表)的归类列表
5.Document类:
- 成员-m_styleSheetCollection: DocumentStyleSheetCollection的实例,数量关系1:1
- 成员-m_styleResover: 匹配css规则的相关类StyleSheetResover的实例,数量关系1:1
规则匹配处理相关类:
1.RuleSet类: 单个css样式表经css解释器之后的结果集,并且按照关键选择器的类型分类
- 成员-m_idRules: 该样式表中的id类型规则
- 成员-m_classRules: 该样式表中的class类型规则
- 成员-m_tagRules: 该样式表中的标签类型规则
- 成员-m_features: 该样式表中的其他特征类型规则
2.DocumentRuleSets类: 各种来源的样式表的合并(用户样式表/作者样式表/默认样式表)
- 成员-m_authorStyle: Ruleset对象的列表,代表作者样式表
- 成员-m_userStyle: Ruleset对象的列表,代表用户样式表
3.StyleSheetResover类: 规则匹配的主要负责类
- 成员-m_ruleSets: DocumentRuleSets类的实例
样式规则匹配
样式规则匹配大致过程
1.StyleResover类以ElementRuleCollector类为工具,为指定的元素匹配规则,并将匹配结果保存到RenderStyle对象中,RenderStyle对象由负责该元素渲染的RenderObject对象管理和使用
2.匹配的输入: StyleResover类中保存的css解释器的解释和分类完毕的样式规则
3.匹配用到的工具类: ElementRuleCollector类
4.被匹配对象: 指定html元素
5.匹配结果: 保存至RenderStyle对象并被RenderObject用于元素渲染
规则匹配的详细过程
说明:
1.关键选择器: 样式规则的选择器字符串中的最右边选择器,它是样式规则在解释后分类的依据
2.匹配过程:
- matchAllRules: 匹配规则的最外层函数,包含匹配默认,用户和作者样式并收集和排序已匹配规则
- matchUARules: 匹配默认样式
- matchUserRules: 匹配用户样式
- matchAuthorRules: 匹配作者样式
3.作者样式匹配详细过程:(默认样式,用户样式的匹配类似)
匹配规则: 从右向左依次匹配选择器
前面我们已经知道解释之后的样式规则是分类存放在对象中的,而为当前元素匹配规则时,也是按id,class,tag,feature顺序依次匹配.
下面我们用伪代码来解释匹配的详细过程:(伪代码不是真正合理的和实际的代码)
1.重要参数
//参数e: 指代被匹配的元素
//重要的变量
var Result=[]; //用于保存完全匹配的结果集
2.工具函数
function firstMatch(property,ruleSet){
//将元素的id/class/tag/feature与idRules/classRules/tagRules/featureRules匹配
//将匹配到的规则以数组返回,未匹配到返回空.
}
function getS(rule){
//获取单条rule规则的选择器数组
}
function Match(s,e){
//将选择器s与元素e匹配
//如果成功匹配则返回true,否则返回false
}
function leftMatch(rule,e){ //第一次匹配过后,用于处理结果集中单条规则的匹配的函数(调用Match函数)
var s = getS(rule); //获取单条规则的选择器数组
for(var i=s.length-1;i>=0;i--){ //从右到左依次将选择器与元素e匹配
var flag = Match(s[i],e);
if(!flag){ //一旦某次匹配失败,函数直接返回
return;
}
}
push(Result,rule); //仅当所有选择器都匹配成功,即完全匹配时,才将该条rule添加到Result
}
function ruleMatch(firstmatch,e){ //第一次匹配后的处理函数(调用leftMatch函数)
if(firstmatch为空){ //第一次匹配为空,直接返回
return;
}
for(var i=0;i<=firstMatch.length-1;i++){
leftMatch(firstMatch[i],e); //第一次匹配不为空,对每条匹配到的规则调用leftMatch
}
}
3.id,class,tag,feature匹配的函数及调用顺序
//匹配idRules的函数
function idMatch(idRules,e){
var firstmatch = firstMatch(e.id,idRules);
ruleMatch(firstmatch,e);
}
//匹配classRules的函数
function classMatch(classRules,e){
var firstmatch = firstMatch(e.class,classRules);
ruleMatch(firstmatch,e);
}
//匹配tagRules的函数
function tagMatch(tagRules,e){
var firstmatch = firstMatch(e.tag,tagRules);
ruleMatch(firstmatch,e);
}
//匹配featureRules的函数
function featureMatch(featureRules,e){
var firstmatch = firstMatch(e.feature,featureRules);
ruleMatch(firstmatch,e);
}
//函数调用顺序
idMatch(idRules,e);
classMatch(classRules,e);
tagMatch(tagRules,e);
featureMatch(featureRules,e);
4.说明
- firstMatch(property,ruleSet)函数: 代表按关键选择器的四种分类进行的第一次匹配,并返回匹配到的结果集(规则的数组)
- Match(s,e)函数: 代表第一次分类匹配后,对结果集内的单条规则中的单个选择器与元素的匹配
- leftMatch(rule,e)函数: 代表第一次分类匹配后,对结果集内的单条规则的所有选择器(从右至左)与元素的匹配
- ruleMatch(firstmatch,e)函数 : 代表第一次分类匹配后,完成接下来所有的匹配任务.
- 元素的内联样式是不经过上述匹配过程的,因为它本身就是专为该元素定义的样式.
权重(优先级)计算
1.选择器字符串的权重(specifishity)
(1)css中的权重模型(I-S-A-B-C)
其中:
I: 指代该规则是否为!important规则
S: 指代该规则是否为内联样式规则
A-B-C: 为内核定义的三类简单选择器
基础部分: A-B-C模型(以webkit为例)
浏览器内核用一个32位二进制数来表示某css规则的权重值,其基础部分的A-B-C模型是指权重计算的三类增量.
- A: id选择器,增量为0x10000
- B: 类选择器,属性选择器和伪类选择器,增量为0x100
- C: 元素选择器和伪元素选择器,增量为1
说明:
- 上述三类增量的定义位于webkit内核中的CSSSelector.h头文件中
- 关于I和S,取值只有0和1,不属于增量模型,我们可以假定为该32位二进制数的最高位和次高位.
- 通用选择器(*),选择器组合符(+,>,~,空格,||)不影响权重值
- 取反伪类 :not()
- 在selector level 3标准(现行标准)中,:not()只接受一个简单选择器为参数,其本身不影响权重,其权重为其参数的权重
- 在selector level 4草案中, :not()接受一个选择器列表为参数,其本身不影响权重,其权重为选择器列表中权重最高的参数的权重.
2.CSS规则权重的计算:
- 选择器字符串中:
- 每出现一个C类简单选择器,权重值增1
- 每出现一个B类简单选择器,权重值增0x100
- 每出现一个A类简单选择器,权重值增0x10000
- 如果是元素的内联规则,次高位置1(笔者假设)
- 如果是!important规则,最高位置1(笔者假设)
- 意义: 高权重值的规则将覆盖低权重规则中的相同属性的值(也就是:设置相同属性的值,高权重有效,地权重失效)
2.涉及到作者样式,用户样式,默认样式三种样式来源时的权重规则
- 作者样式/网页作者样式(author style sheets): 网页作者规定的样式(网页样式的主要来源)
- 用户样式(user style sheets): 用户自定义的个性样式(各大浏览器都在自行废除中)
- 默认样式/浏览器样式(user agent style sheet): 用户代理的默认样式(一般用于前两种都未涉及到的元素的样式)
一般,网页开发者和大多数用户考虑到的只有作者样式表和默认样式表(例如:用选择器*去掉默认样式中的元素margin和padding),而默认样式表中不含任何内联样式和!important样式.但是如果我们考虑上用户样式,权重规则可能会有一点不和谐的地方:(优先级从大到小)
用户样式!important规则 > 作者样式!important规则 > 内联样式 > 作者样式普通规则 > 用户样式普通规则
上面的优先级链中不包含内联!important规则,是因为一般的!important规则的目的就是为了以外部样式覆盖内联样式.
可见, 在普通规则和!important规则上, 两种样式表的权重情况是不同的.
- 一般规则: 作者样式 优先于 用户样式
- !important规则: 用户样式 优先于 作者样式
可能正是这样的不和谐,才使得各大浏览器都在逐渐废除用户样式吧.但是用户样式的实现可以借助浏览器插件间接实现,不过那又是另外一个故事了.
权重相同时的覆盖原则
前面说到: 相同属性设置时,高权重覆盖低权重.那么如果两条规则的权重相同时如何决定哪个有效哪个无效呢?
首先,这里的权重相同有两层含义:
- 基础的基于A-B-C模型的权重计算结果相同
- 在是否为内联样式或!important规则上的表现也相同
那么,权重相同的情况有下面几种:
1.同一外部样式表中的同权重规则
2.不同样式表中的同权重规则(两部分)
- 两样式表A和B均是通过link或style引入
- 样式表A通过@import规则导入样式表B
- 样式表A,B均是通过link或style引入,但样式表C是B通过@import导入
3.元素class属性为多个值,且各个值同权重时
css2.1规范指出: 如果两个声明的权重,来源都相同,后指定的生效. 通过@import引入的样式表中的规则被认为位于父样式表自身的所有规则之前.
而我们讨论同权重规则的覆盖,就是对这个后指定的理解与解读:
- 对于1情况,后指定意为靠后的(后面的覆盖前面的)
- 对于2情况
- A,B均是link/style引入: 后指定,意思是导入样式表的link/style标签在html文档中相对靠后的位置
- A通过@import规则导入B: 相对于B,A为后指定
- A,B是link/style引入,B通过@import导入C
- 在html文档中,A的link比B的link靠前: 同权重规则优先级为B>C>A
- 在html文档中,B的link比A的link靠前: 同权重规则优先级为A>B>C
- 对于3情况: 经过测试,各个class值的先后顺序不影响覆盖顺序,覆盖顺序的判断仍按照上面两个步骤.
下面是一些测试代码:
/*测试1: 同一样式表内同权重规则+覆盖规则与class内值先后顺序无关*/
/*html部分:
<div class="a b"></div>
*/
div{
width: 100px;
height: 100px;
border: 1px solid black;
}
.b {
background-color: blue;
}
.a {
background-color: red;
}
/*测试结果: 红色*/
/*测试2: 不同样式表,相同权重规则*/
/*test1:<link>位于<style>之前*/
/*html部分:
<link rel="stylesheet" href="csstest2.css">
<div class="a"></div>
<style type="text/css">
.a{
background-color: red;
}
</style>
*/
div{
width: 100px;
height: 100px;
border: 1px solid black;
}
.a {
background-color: blue;
}
/*测试结果: 红色*/
/*test2:link位于style之后*/
/*html部分:
<div class="a"></div>
<style type="text/css">
.a{
background-color: red;
}
</style>
<link rel="stylesheet" href="csstest2.css">
*/
div{
width: 100px;
height: 100px;
border: 1px solid black;
}
.a {
background-color: blue;
}
/*测试结果: 蓝色*/
/*test3: ABC覆盖规则*/
/*html部分:
<div class="a"></div>
<style type="text/css">
.a{
background-color: blue;
}
</style>
<link rel="stylesheet" href="csstest2.css">
*/
/*csstest3.css内容
@charset utf-8;
.a {
background-color:yellow;
}
*/
@import "csstest3.css"; /*必须注释掉前面所有的测试内容,否则违反了@import的使用规则*/
div{
width: 100px;
height: 100px;
border: 1px solid black;
}
.a {
background-color: red;
}
/*测试结果:
不作注释: 红色
注释csstest2.css: 黄色
注释csstest2.css和csstest3.css: 蓝色
*/
从webkit内核简单看css样式和css规则优先级(权重)的更多相关文章
- 【前端】webkit内核浏览器DIV滚动条样式修改和设置
webkit内核浏览器DIV滚动条样式修改和设置 引言: 最近在做自己的小项目,为了设计出好看的页面费劲了心思,大到页面的整体布局,小到DIV的滚动条都不放过,以下是我通过查阅资料总结的webkit内 ...
- HTML+CSS样式设置——CSS一学就会
HTML+CSS样式设置 CSS:(Cascading Style Sheets)层叠样式设置表. 网页的展示效果跟其排版有非常大的关系.排版则主要依靠CSS来设置.调节. 以下说CSS与HTML的联 ...
- css3中webkit内核的滚动栏样式
项目其中用到的滚动栏样式,在别人的基础上调成适合自己的样式.(IE能够调试滚动栏样式,firefox眼下不能调试) ::-webkit-scrollbar { width: 14px; }/* Tra ...
- 简单了解css3样式表写法和优先级
css3和css有什么区别?首先css3是css(层叠样式表)技术的升级版本,而css是一种用来表现HTML(标准通用标记语言的一个应用)或XML(标准通用标记语言的一个子集)等文件样式的计算机语言. ...
- CSS:CSS样式表及选择器优先级总结
我们在写网页的时候经常会遇到同一个HTML文件,使用了外部样式.内部样式以及内联样式,那么如果发生冲突时浏览器是怎么抉择的呢? 也会遇到这样的情况,在样式表中,对同一个HTML元素,我们有可能既用到了 ...
- 用JS改变的元素CSS样式,css里display :none 隐藏 block 显示
CSS样式的引用有3种方式:style引用.class引用.id引用,所以js改变元素的样式我们也分3种来说. 1.js改变由style方式引用的样式:方法一:document.divs.style. ...
- (day44)css样式、css布局
目录 一.css样式 (一)文字样式 (1)文字字体font-family (2)字体大小font-size (3)字体粗细font-weight (4)字体颜色color (二)文本样式 (1)文字 ...
- css的层叠性+继承性+优先级+权重
一.层叠性 1.含义 多种css样式叠加,浏览器处理冲突的能力. 2.原则 1>一般情况下,若出现冲突,会按照css的书写顺序,以最后的样式为准 2>样式不冲突,就不会层叠 二.css的继 ...
- HTML5入门(CSS样式-------------------(CSS基础知识点----------------------------))
CSS继承性+层叠性+盒子+浮动 一.CSS继承性 eg: <style> div{ ...
随机推荐
- 有趣的bug——Java静态变量的循环依赖
背景 是的,标题没有错误,不是Spring Bean的循环依赖,而是静态变量之间的循环依赖. 近期的项目均是简单的Maven项目,通过K8S部署在阿里云上,其配置文件读取规则如下所示: (1) 优先读 ...
- BayaiM__linux双网卡绑定文档
BayaiM__linux双网卡绑定文档 开门贱山:以下内容纯属原创,如有雷同,爱咋咋滴吧~~!!—————————————————————————————————————————— 1,备份网卡信息 ...
- [日常] 前端资源测试机上忽略版本号的的nginx配置
利用nginx的rewrite的指令,可以实现url的重新跳转,rewrtie有四种不同的flag,分别是redirect(临时重定向).permanent(永久重定向).break和last.其中前 ...
- 数据库(update tab1 set tab1.name=tab1.name+(select t2.name from tab2 t2 where t2.id=tab1.id))
有t1 和 t2 两个表,表中的数据和字段如下: 执行 如下SQL语句: update tab1 set tab1.name=tab1.name+(select t2.name from tab2 t ...
- centos7下安装配置prometheus
prometheus官网:https://prometheus.io/download/ 搭建环境参考:https://blog.csdn.net/baidu_36943075/article/det ...
- day65_10_9vue循环指令与组件
一.v-once v-once指令赋值给标签后,这个标签中的所有变量都不能被更改,只能被渲染一次.之后的改动不能改变该标签中的值: <div id="app"> < ...
- [C3] Andrew Ng - Neural Networks and Deep Learning
About this Course If you want to break into cutting-edge AI, this course will help you do so. Deep l ...
- 牛客小白月赛18 Forsaken给学生分组
牛客小白月赛18 Forsaken给学生分组 Forsaken给学生分组 链接:https://ac.nowcoder.com/acm/contest/1221/C来源:牛客网 Forsaken有 ...
- ABP docker发布
环境:CentOS 7.6 64位 linux基本命令: cd:进入某个文件夹 mkdir:创建文件夹 ls:显示文件 ll:罗列出当前文件或目录的详细信息 判断是文件 还是文件夹: Linux系统中 ...
- Dockerfil
Dockerfile简介 dockerfile 是一个文本格式的配置文件, 用户可以使用 Dockerfile 来快速创建自定义的镜像,另外,使用Dockerfile去构建镜像好比使用pom去构建ma ...