正确理解 CSS 权值(不应存在进制)

news/2024/11/29 19:48:58/

这是我的博客。
欢迎在 freeCodeCamp 社区阅读原文。

前言

直接说结论,CSS 选择器(selector)的权值(以下直接称为“CSS 权值”)不应以进制来理解,因此进制既不是 10,100,也不是 256。
笔者看到过很多文章,发现有很大一部分人认为 CSS 权值是 256 进制甚至是 10 进制的。
下文首先解释 CSS 权值应该如何正确理解,然后尝试解释为何有人会理解为 256 进制。
本文代码运行环境:

  • Google Chrome 版本 80.0.3987.149(正式版本)
  • Firefox 74.0 (64 位)
  • Opera 版本:67.0.3575.97
  • Safari 版本13.0.2 (15608.2.30.1.1)
  • 抱歉无法在 Edge 和 IE 上测试

1、何为 CSS 权值?如何正确理解与比较?

1.1 定义

Specificity is the means by which browsers decide which CSS property values are the most relevant to an element and, therefore, will be applied. Specificity is based on the matching rules which are composed of different sorts of CSS selectors. (MDN web Docs)

If there are two or more conflicting CSS rules that point to the same element, the browser follows some rules to determine which one is most specific and therefore wins out. Think of specificity as a score/rank that determines which style declarations are ultimately applied to an element. (w3schools)

在英文文档中,用 Specificity 这个单词来描述所谓的 CSS 权值。

Specificity 是“特异性”的意思,CSS Specificity 是应用于 CSS 选择器的规则集,以确定哪些样式应用于元素。简单地说就是特异性决定了哪些样式起作用。那么应该如何理解以及比较呢?

1.2 理解及比较

Every selector has its place in the specificity hierarchy. There are four categories which define the specificity level of a selector.

每个选择器在特异性层次结构中都有其位置。 有四个类别定义了选择器的特异性级别。
那么我们可以理解为 A, B, C, D 四个类别,初始各个位置都是 0,即 0,0,0,0。
有一张图描述得很好:

四个类别:

  • A: 内联样式,写在 HTML 标签中的 style="",属于 A 类。若有,那么 A 位置加一,可以理解为 1,0,0,0。
  • B: id 选择器(如 #id1),如 id="",属于 B 类,若有,那么 B 位置加一。即 0,1,0,0。
  • C: 类选择器(如 .class1)、伪类(如 :hover)、属性(如 [ type=“radio” ])为 C 类。有则 C 位置加一,即 0,0,1,0。
  • D: 标签(如 div),伪元素为 D 类,若有则 D 位置加1,即 0,0,0,1。

规律与注意事项

Universal selector (*), combinators (+, >, ~, ‘’, ||) and negation pseudo-class (:not()) have no effect on specificity. (The selectors declared inside :not() do, however.)

  • 通配符选择器 (*),组合选择器 (+, >, ~, ‘’, ||) 和否定伪类 (: not ( )) 对特异性没有影响。但是在:not( )内部声明的选择器可以。

When an important rule is used on a style declaration, this declaration overrides any other declarations.

  • !important 是一种特殊的声明,它的级别高于其他所有的普通声明。这个链接里有一些关于 !important 的使用注意事项,中文资料也很多,不再赘述。

  • 比较时,A, B, C, D 四位依次比较,A 较大的权重大,不用看后面。当 A 相同时,比较 B。以此类推。

  • 当 A, B, C, D 相同时,后面的规则会覆盖前面的规则。

A class selector beats any number of element selectors

  • 一个类选择器可以击败任意数目的元素选择器。这就说明进制的概念在理论上是不应存在的。即 0, 0, 1, 0 应大于 0, 0, 0, D。 D 可以取任意值。因此比较权重时,还是应该按位去比。

这个链接里也有一张有意思的图,方便大家理解。

1.3 举例说明

  body div {/*此处权重 = 0,0,0,2*/background-color: red;}div {/*此处权重 = 0,0,0,1*/height: 100px;width: 100px;background-color: green;}<div>Test CSS Specificity</div>

    div {width: 100px;height: 100px;}.testClass.testClass {/*权重为0,0,2,0*/background-color: yellow;}.testClass {/*权重为0,0,1,0*/background-color: black;}<div class="testClass">Test CSS Specificity</div>

这里显示为黄色,说明重复的类选择器权重也会累计。

    div{width: 100px;height: 100px;}.testClass.testClass {/*权重为0,0,2,0*/background-color: yellow;}.testClass {/*权重为0,0,1,0*/background-color: black;}#testClass {/*权重为0,1,0,0*/background-color: blue;}      <div class="testClass" id="testClass">Test CSS Specificity</div>

各种各样的例子网上很多,不再赘述。下面第二部分举一些反例证明进制的思想是不合适的。

2、为何进制不是10,100或256呢?

2.1 反例

十一个类选择器,与一个 id 选择器。显而易见的,进制并不是 10。最后还是 id 选择器奏效。

div{width: 100px;height: 100px;
}
#testId {/*权重为0,1,0,0*/background-color: purple;
}      .testClass1.testClass2.testClass3.testClass4.testClass5.testClass6.testClass7.testClass8.testClass9.testClass10.testClass11 {/*权重为0,0,11,0,并没有任何作用*/background-color: red;
}<div class="testClass1 testClass2 testClass3 testClass4 testClass5 testClass6 testClass7 testClass8 testClass9 testClass10 testClass11" id="testId">Test CSS Specificity</div>

256个类选择器能干掉一个 id 选择器吗?

#id {/*权重为0,1,0,0*/background: red;
}.c000.c001.c002.c003.c004.c005.c006.c007.c008.c009.c010.c011.c012.c013.c014.c015.c016.c017.c018.c019.c020.c021.c022.c023.c024.c025.c026.c027.c028.c029.c030.c031.c032.c033.c034.c035.c036.c037.c038.c039.c040.c041.c042.c043.c044.c045.c046.c047.c048.c049.c050.c051.c052.c053.c054.c055.c056.c057.c058.c059.c060.c061.c062.c063.c064.c065.c066.c067.c068.c069.c070.c071.c072.c073.c074.c075.c076.c077.c078.c079.c080.c081.c082.c083.c084.c085.c086.c087.c088.c089.c090.c091.c092.c093.c094.c095.c096.c097.c098.c099.c100.c101.c102.c103.c104.c105.c106.c107.c108.c109.c110.c111.c112.c113.c114.c115.c116.c117.c118.c119.c120.c121.c122.c123.c124.c125.c126.c127.c128.c129.c130.c131.c132.c133.c134.c135.c136.c137.c138.c139.c140.c141.c142.c143.c144.c145.c146.c147.c148.c149.c150.c151.c152.c153.c154.c155.c156.c157.c158.c159.c160.c161.c162.c163.c164.c165.c166.c167.c168.c169.c170.c171.c172.c173.c174.c175.c176.c177.c178.c179.c180.c181.c182.c183.c184.c185.c186.c187.c188.c189.c190.c191.c192.c193.c194.c195.c196.c197.c198.c199.c200.c201.c202.c203.c204.c205.c206.c207.c208.c209.c210.c211.c212.c213.c214.c215.c216.c217.c218.c219.c220.c221.c222.c223.c224.c225.c226.c227.c228.c229.c230.c231.c232.c233.c234.c235.c236.c237.c238.c239.c240.c241.c242.c243.c244.c245.c246.c247.c248.c249.c250.c251.c252.c253.c254.c255 {/*权重为0,0,256,0,并没有任何作用*/background: blue;
}test {display: block;height: 100px;width: 100px
}
<test id="id" class="c000 c001 c002 c003 c004 c005 c006 c007 c008 c009 c010 c011 c012 c013 c014 c015 c016 c017 c018 c019 c020 c021 c022 c023 c024 c025 c026 c027 c028 c029 c030 c031 c032 c033 c034 c035 c036 c037 c038 c039 c040 c041 c042 c043 c044 c045 c046 c047 c048 c049 c050 c051 c052 c053 c054 c055 c056 c057 c058 c059 c060 c061 c062 c063 c064 c065 c066 c067 c068 c069 c070 c071 c072 c073 c074 c075 c076 c077 c078 c079 c080 c081 c082 c083 c084 c085 c086 c087 c088 c089 c090 c091 c092 c093 c094 c095 c096 c097 c098 c099 c100 c101 c102 c103 c104 c105 c106 c107 c108 c109 c110 c111 c112 c113 c114 c115 c116 c117 c118 c119 c120 c121 c122 c123 c124 c125 c126 c127 c128 c129 c130 c131 c132 c133 c134 c135 c136 c137 c138 c139 c140 c141 c142 c143 c144 c145 c146 c147 c148 c149 c150 c151 c152 c153 c154 c155 c156 c157 c158 c159 c160 c161 c162 c163 c164 c165 c166 c167 c168 c169 c170 c171 c172 c173 c174 c175 c176 c177 c178 c179 c180 c181 c182 c183 c184 c185 c186 c187 c188 c189 c190 c191 c192 c193 c194 c195 c196 c197 c198 c199 c200 c201 c202 c203 c204 c205 c206 c207 c208 c209 c210 c211 c212 c213 c214 c215 c216 c217 c218 c219 c220 c221 c222 c223 c224 c225 c226 c227 c228 c229 c230 c231 c232 c233 c234 c235 c236 c237 c238 c239 c240 c241 c242 c243 c244 c245 c246 c247 c248 c249 c250 c251 c252 c253 c254 c255">test 256</test>

这个 256 的测试代码修改自张鑫旭的一篇博客。
结果显而易见,256 个 class 并不能“击败”一个 id,所以进制不是 256。
100 就不再试了。所以进制的说法,从实际看来,也是不合适的。

BUT!你可以发现,在张鑫旭的这篇博客中(2012 年 08 月 20 日),256 个类选择器确实干掉了一个 id 选择器!那也就是说,进制的说法至少在当时是有据可依的。那具体是为什么呢?结合我搜索到的资料,简单的“猜想”一下。

2.2 为什么会有进制的说法?

通过张鑫旭博客,我们可以看到,在当时,确实 256 个类选择器干掉了一个 id 选择器。

在这篇博客中,他提到了:

据说,查看FireFox浏览器的源代码,发现,所有的类名(classes)都是以8比特数据类型存储的。对比特稍稍了解的人都知道,8比特所能hold的最大值就是255. 所以你想啊,当同时出现256个class, 势必会越过其边缘,溢出到id区域。

Gecko overflows the count of classes into the count of IDs, each of which holds 8 bits.

— Cameron McCormack (@heycam) August 16, 2012

根据一个Opera员工的信息,Opera浏览器class类名是以16比特数据类型存储的。因此,该浏览器要想发生class溢出到id的话,需要连续65536个class. 也不知道是不是因为16比特字符串比8自己的更影响选择器引擎

yes, opera uses 16 bits instead of 8. bring on 65536 classes…

— patrick h. lauke (@patrick_h_lauke) August 16, 2012

也就是说,虽然标准是那么规定的,但是落实到浏览器上,实际效果确是不尽相同。
因此我个人认为,这种不存在进制的,按级别按位比较的方式,应该更合理一些。


写在最后:
以上是我个人的理解,欢迎批评指正。
大家如对 CSS 的其他话题感兴趣,也欢迎通过我的邮箱与我交流学习。


http://www.ppmy.cn/news/382817.html

相关文章

微信小程序知识云开发

一个小程序最多5个服务类目&#xff0c;一个月可以修改3次类目 小程序侵权投诉的发起与应对 软件著作权作品登记证书 实现小程序支付功能 如何借助官方支付api简单、高效率地实现小程序支付功能 借助小程序云开发实现 只需要一个简单的云函数 实现微信小程序支付功能 ex…

【Vue】从量子链网页钱包看vue项目结构以及开发部署最佳实践

项目介绍 qtum-web-wallet 是量子链推出的网页版钱包。 项目地址 https://github.com/qtumproject/qtum-web-wallet 项目采用vue搭建。 通过网页可以实现钱包的创建备份转账以及智能合约的部署调用功能。 项目结构 这个vue项目采用了vue-loader,所以整体用的是嵌套结构。 b…

Android P中的AVB校验

avb校验功能主要是由external/avb/libavb库实现的&#xff0c;该库主要完成的工作包括各个分区镜像的校验&#xff0c;签名验证&#xff0c;以及vbmeta数据的解析&#xff0c;包括了各种flags的处理以及dm-verity所需要的参数解析。avb校验库的主入口为 avb_slot_verify(AvbOps…

Android P 如何挂载system镜像到根目录

Android O/P 版本以来&#xff0c;谷歌加入了A/B system的特性&#xff0c;此时ramdisk和system是一起放在同一个system.img镜像中的。而系统起来之后也就不存在system分区了&#xff0c;而是直接把system镜像挂载到/根目录上。那么这个操作是怎么进行的呢&#xff1f; system.…

[转载型] Neutron 系列 (17): Neutron 分布式虚拟路由【上】

http://www.aboutyun.com/forum.php?modviewthread&tid16860&highlightneutron%2B%2B%CF%B5%C1%D0 1.路由的相关知识有哪些&#xff1f; 2.Neutron 的传统和 DVR Router是什么&#xff1f; 3.DVR的功能有哪些&#xff1f; Neutron 作为 OpenStack 一个基础性关键服务&…

[连载型] Neutron 系列 (17): Neutron 分布式虚拟路由【上】

问题导读&#xff1a; 1.路由的相关知识有哪些&#xff1f; 2.Neutron 的传统和 DVR Router是什么&#xff1f; 3.DVR的功能有哪些&#xff1f; Neutron 作为 OpenStack 一个基础性关键服务&#xff0c;高可用性&#xff08;HA&#xff09;和扩展性是它的基本需求之一。对 neut…

DVR

eutron 系列 (17): Neutron 分布式虚拟路由【上】 [复制链接] 电梯直达 楼主 发表于 2016-1-4 14:56:36 | 只看该作者 |只看大图 大数据系列零基础由入门到实战视频大优惠 本帖最后由 eying 于 2016-1-13 16:59 编辑 问题导读&#xff1a; 1.路由的相关知识有哪些&#x…

Neutron 分布式虚拟路由(Neutron Distributed Virtual Routing)

本系列会分析OpenStack 的高可用性&#xff08;HA&#xff09;概念和解决方案&#xff1a; &#xff08;1&#xff09;OpenStack 高可用方案概述 &#xff08;2&#xff09;Neutron L3 Agent HA - VRRP &#xff08;虚拟路由冗余协议&#xff09; &#xff08;3&#xff09;…