对于 csser 来说,多多少少都会遇到过 “样式规则不生效?”、“样式规则被覆盖?” 等等问题,这些都与 CSS 权重有关系 。
我自己是一名从事了多年开发的web前端老程序员,目前辞职在做自己的web前端私人定制课程,今年年初我花了一个月整理了一份最适合2019年学习的web前端学习干货,各种框架都有整理,送给每一位前端小伙伴,想要获取的可以关注我的头条号并在后台私信我:前端,即可免费获取选择器匹配原理
在此之前,容我先简单介绍浏览器是怎么通过各种选择器,把样式规则和 DOM 元素扯上关系的 。
浏览器中存在着专门的渲染引擎来渲染 html 文档 。这里以 Webkit 内核为例,在启动渲染流程时,引擎一方面会解析 HTML 文档,构建 DOM 节点树(DOM Tree),另一方面会解析样式文件生成 样式规则(Style Rules),然后结合分析 DOM 树和样式规则生成 渲染树(Render Tree),最后 布局 和 绘制 出 UI 界面 。
文章插图
Webkit 渲染流程(摘自 https://www.html5rocks.com/en/tutorials/internals/howbrowserswork/)
CSS 的选择器匹配就发生在 渲染树 的构建过程 。浏览器会从 DOM 树的根节点开始遍历每个可见节点,对于每个可见节点都会在规则表中查找适配的样式规则 。那么,如此庞大的样式数据和复杂的选择器结构,渲染引擎是怎么寻找到适配当前元素的样式规则呢?
请看下面这个复合选择器 。如果引擎是按照从左向右的顺序匹配选择器,将会导致大量 回溯的发生:先是在当前节点到 DOM 树跟节点的路径上寻找 div 元素,然后沿着分支路径继续往下找第二个 div 元素,如果当前路径找不到,就得回退到上一个 div 元素尝试另一条分支路径 。如此往复,对性能损耗将会非常严重 。
div div span .text {}所以,引擎是采取 从右向左 的顺序来匹配选择器 。也就是 从最具体的选择器开始,如果与当前节点不匹配,则直接抛弃该条规则;如果匹配,只需要沿着路径往上确认其他选择器是否也匹配,这样做可以大大减少无效的匹配数,提高性能 。除此之外,引擎还会把不同类型的选择器(id、class、tag 及其他类型)归类到哈希表中,进一步减少查找基数 。
了解选择器的匹配原理,有利于我们理解其权重规则,对于编写简洁、高效的 CSS 代码非常有帮助 。
CSS 权重
通过不同的方式(内联样式、外部样式表)、不同类型的选择器组合针对某个元素声明样式规则时,如何决定最终哪个声明会被应用到元素上?这就涉及到 CSS 权重(也指优先级,Specificity) 。
围绕 CSS 权重主要有以下三条规则:
- 权重不同的样式规则作用于同一元素时,权重高的规则生效;
- 权重相同的样式规则作用于同一元素时,后声明的规则生效;
- 选择器在 DOM 中的位置关系不会对规则产生影响 。
文章插图
- 这里的 body 标签元素在 DOM 中离目标 div 更近,但最后还是按照样式规则的声明顺序来决定 。
- 直接作用于元素的样式规则优先级高于从祖先元素继承的规则;
文章插图
如何比较不同选择器的权重高低?这里划分成 5 个权重等级,按照等级 由高到低 的顺序:
- !important 关键字
- 内联样式
#demo {}类选择器、属性选择器、伪类选择器
.demo {}[type="text"] {}div:hover {}div:first-child {}需要注意,否定伪类(:not())比较特殊,它不会对权重产生影响,但是 否定伪类内部的选择器会影响权重 。
<html> <head> <style> div#demo span { color: red; } div:not(#demo) span { color: blue; } </style> </head> <body> <div id="demo"> <span>普通 demo</span> <div id="pseudo"> <span>否定伪类 demo</span> </div> </div> </body><html>
推荐阅读
- IDW ArcGIS反权重空间插值视频教程和文字版教程
- PHP中$_SERVER详解参数&说明
- __FILE__ php dirname 详解
- 详解阿里云数据中台
- 磁盘分区对齐详解与配置
- 光纤适配器面板型号详解 光纤适配器的特点
- 终于有人把 Docker 讲清楚了,万字详解
- 家用无线路由器信号分为2.4G和5G,区别在哪呢?详解
- linux系统ncat命令详解
- 详解Mysql数据库不同字符集下迁移方法