详解CSS优先级计算及层级嵌套关系
你真的理解CSS优先级计算及层级嵌套关系么
你真的理解CSS优先级计算及层级嵌套关系么?
如果是以前的我,肯定会天真地说出不就是样式选择器的嵌套而已么,考虑下优先级就是 #id > .class类 > 属性选择器 > 标签选择器,在此优先级的基础上再一层层去判断比较就行了,对CSS很自信的我直到某天被一位BAT的面试官问了一道层级嵌套的题目并答错后,才发现CSS的优先级及层级嵌套关系远远没想像的这么简单,其中蕴含着许多的知识点都是被我们平时所忽略的,那么,换做是你的话,你觉得你自己是否真的理解CSS的优先级计算及层级嵌套呢,如果不清楚的话,那么我立马给你上几道开胃菜吃一吃~
给大家3分钟的时间思考下下面的题目,最终span元素的 abc 将显示出什么颜色?
Question1
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Question1</title><style> .outer.c .b .d { color: red; } #a .b .d { color: blue; } .c .b .d { background: green; } #a .d { background: gray; } </style></head><body><div class="outer c" id="a"><p class="b"><span class="d">abc</span></p></div></body></html>
好了,上述答案是 blue 蓝色。
相信这题做对的同学还是比较多的,那我们再稍稍进阶一下,复杂一下,你觉得下面这段代码最终显示出来的 123 颜色又是什么呢?
Question2
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Question1</title><style> .c1 .c2 .c3{ color: red; } .c1 #id2 .c3{ color: blue; } div#id2 .c3{ color: grey; } #id1 .c2 .c3{ color: yellow; } #id1.c1 .c2{ color: green; } </style></head><body><div class="c1" id="id1"><div class="c2" id="id2"><p class="c3">123</p></div></div></body></html>
答案是?
是的,这里给大家留个悬念,看完这篇文章后,你再来重新计算判断下你的新结果跟你起初的结果是否一样,看看是不是掌握了本文的知识点。
那么我们就进入正题吧!
说到CSS选择器的层级嵌套,在项目比较小,代码量比较少的时候,出现层级嵌套的情况并不多,但当你的项目逐渐扩大,随着样式逐渐增多,页面的标签元素或多或少就开始会受到其他样式的污染,这些影响可能来自周围其他样式文件,也有可能来自自身,拿Vue技术栈来说,如果你的样式不加 scoped 标识进行样式局部化的话,当项目规模扩大时出现样式污染就尤为明显,进而就需要我们去了解如何通过比较层级嵌套去计算CSS样式的优先级大小,来命中我们所需要的样式。
CSS优先级
说到CSS优先级,它有哪些计算规则呢?
1、祖先样式择近优先
说到祖先样式我们就得提一下CSS的继承性了
CSS继承性
<div style="color: blue"><div>123<div>234</div></div></div>
比如上面这段代码,未设置明确样式的子元素都会继承最外层父元素的的字体颜色 blue,
也就是说 123 和 234 显示的都是蓝色,这就是其继承性。<div style="color: blue;"><div style="color: red;">123<div>234</div></div></div>
但是,当你在第二层的div加上样式后,最里层的div元素继承的样式其实是离它最近的div的样式,也就是红色,这就是计算CSS优先级第一个规则,我们把一个元素标签从祖先那里继承来的而自身没有的样式属性叫做"祖先样式",而自身直接拥有的属性则称为"直接样式"。
所以这里就有了第二个规则
2、直接样式优先级永远高于祖先样式
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Question1</title><style> #id1{ color: green; } .c2{ color: blue; } #id1.c1{ color: red !important; } </style></head><body><div class="c1" id="id1"><p class="c2">ABC</p></div></body></html>
看下上面这段代码,!important字段是不是格外地入眼,这时你或许会认为最终的样式是红色,然后最终样式却是蓝色
这是因为 c2 这个类直接指名到了p元素上,也就是p元素具有自身的直接样式,所以其优先级是最高的,只要是相同的样式属性,直接样式始终大于祖先样式。
理解完前俩个规则,那么我们计算优先级时最先看的便是层级样式是否具体到指定的元素上,也就是给其定义了直接样式,接着才进入到我们层级嵌套判断规则,所以,接下来的规则介绍,我们将建立在标签已有直接样式的基础上,OK,那我们接着往下讲规则3。
Question3
首先让我们先来回顾下CSS有哪些选择器:
ID 选择器, 如 #id{}
类选择器, 如 .class{}
属性选择器, 如 a[href="37.com"]{}
伪类选择器, 如 :hover{}
伪元素选择器, 如 ::before{}
标签选择器, 如 span{}
通配选择器, 如 *{}
当一个元素标签被多个选择器命中时,便有了我们的第三个规则
3、选择器优先级
内联样式 > ID 选择器 > 类选择器 = 属性选择器 = 伪类选择器 > 标签选择器 = 伪元素选择器
当然,如果你在上述某一个选择器的样式里加了 !important ,那么改样式属性的优先级是最高的,多个 important 的话就按照先后顺序来了。
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Question1</title></head><style> #id1{ color: red; } .c1{ color: green; } div{ color: black; } </style><body><div style="color: blue;" id="id1" class="c1">123</div></body></html>
如上图,抛开加了important的标签选择器,优先级最高的便是内联样式,接着是ID、类、标签选择器。
看到这里,这时你肯定会问:实际项目中很少直接一个选择器的,正常都是多层嵌套的CSS,来保证样式的命中精确,是的没错,这里我们所运用的便是CSS的后代选择符,而这里也就是我们所说的层级嵌套了,也是本文最核心的部分。
我们来看下CSS的选择符,其共有三种,分别为:
后代选择符(子孙元素):.a .b{}
子选择符(直接子元素):.a > .b{}
相邻选择符(兄弟元素):.a + .b{}
当我们一个标签元素被多个选择符所命中,那么要应用哪个CSS样式,就需要去计算哪个层级嵌套关系(即选择符)的优先级更高了,所以就有了我们的计算规则4:
4、选择符权重大小
首先计算每条选择符中ID选择器的数量和为 a,计算选择符中类选择器、属性选择器以及伪类选择器的数量和为 b,计算选择符中标签选择器和伪元素选择器的数量和为 c,按 a、b、c的顺序依次进行比较,下一位比较的前提是上一位数量相同的情况下,谁大谁优先级高,一样大时则按样式位置先后顺序(后覆盖前)进行渲染,越后面优先级越高。
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Question1</title></head><style> #id1 .c2{ color: red; } .c1 .c2{ color: green; } p.c2{ color: black; } </style><body><div id="id1" class="c1"><p class="c2">123</p></div></body></html>
当然不管你层级嵌套的规则算出来优先级如何,内联样式的优先级还是更大的,当然 !important 的优先级无线高,比内联还高,除非内联也是 !imporant 23333~
如果有去了解过CSS层级嵌套的读者的话,应该还知道网上还有一种数值权重的说法,也就是
!important (权重无限)
内联样式 (权重1000)
ID选择器 (权重100)
类选择器、属性选择器、伪类选择器(权重10)
标签选择器、伪元素选择器(权重1)
然后通过去计算选择符的权重值来判断哪个选择符的优先级高,这种方法来说确实是相对比较生动形象,但其实里面是有错误的,比如11个类选择器组成的选择符和1个ID选择器组成的选择符,按理计算出来的权重进行比较是 110 > 100,应该应用11个类选择器的样式才是,而实则用的是ID选择器的样式,这是因为
权重的进制是并不是十进制,CSS 权重进制在 IE6 为 256,后来扩大到了 65536,现代浏览器则采用更大的数量
按这么计算的话至少得256个类选择器才能比拟一个ID选择器,所以你可以理解为每种选择器的权重总值都被设上了一个阀值,不过你再多个,终归不能超过这个阀值,继续拿上面例子来说,比ID选择器优先级低的选择器,不管数量再多,其权重总值永远都无法达到ID选择器的权重值,也就是到达99.99时就封顶了,类选择器和标签选择器也是同理,所以样式应用的是1个ID选择器的选择符所对应的样式。
最后,最后的规则便是
5、!important 地位最高、永远的神!
在同一样式属性都有 !important 的前提下,才继续使用层级嵌套的计算规则计算优先级,不然它的地位就是无限高。
结尾
好了,那么本篇内容就差不多讲完了,在了解完CSS的优先级计算和层级嵌套关系后,现在让我们再回到我们一开始的第二道题目,现在的你重新计算下,看看最终数字 123 的字体颜色是否跟你的最初的认为的颜色是否一致,如果是一致的话,那你CSS的基本功很不错哟~ 继续巩固,如果不一致,希望这篇文章能帮你弥补知识点,查漏补缺,纠正日常被我们所忽略的错误。
以上就是本篇文章的所有内容,是不是觉得CSS知识相对之前文章趣味一些,那么敬请期待后续的CSS相关知识文章~
感谢您的阅读,如有技术疏漏、不对的地方欢迎纠正指教,谢谢!