CSS选择器世界

978-7-115-51722-7
作者: 张鑫旭
译者:
编辑: 杨海玲
分类: CSS/CSS3

图书目录:

详情

本书几乎所有的内容都是其他地方(线上资源或者图书中)都看不到的。CSS有别于传统的语言,其各个属性的表现和行为相互间是参杂在一起的,是很难一个一个分开的,如果强制分开,就是一个参考文档。所以,要想把错综的CSS知识讲好,就必须以一种“世界观”的眼界去看待它。CSS选择器作为CSS世界的支柱,其作用好比人类的脊柱,其与HTML结构、浏览器行为、用户行为以及整个CSS世界是相互依存、相互作用的。

图书摘要

版权信息

书名:CSS选择器世界

ISBN:978-7-115-51722-7

本书由人民邮电出版社发行数字版。版权所有,侵权必究。

您购买的人民邮电出版社电子书仅供您个人使用,未经授权,不得以任何方式复制和传播本书内容。

我们愿意相信读者具有这样的良知和觉悟,与我们共同保护知识产权。

如果购买者有侵权行为,我们可能对该用户实施包括但不限于关闭该帐号等维权措施,并可能追究法律责任。

著    张鑫旭

责任编辑 杨海玲

人民邮电出版社出版发行  北京市丰台区成寿寺路11号

邮编 100164  电子邮件 315@ptpress.com.cn

网址 http://www.ptpress.com.cn

读者服务热线:(010)81055410

反盗版热线:(010)81055315


CSS选择器是CSS世界的支柱,撑起了整个精彩纷呈的CSS世界。本书专门介绍CSS选择器的相关知识。在本书中,作者结合多年从业经验,在CSS基础知识之上,充分考虑前端开发人员的开发需求,以CSS选择器的基本概念、优先级、命名、最佳实践以及各伪类选择器的概述和适用场景为技术主线,为CSS开发人员介绍有竞争力的知识和技能。此外,本书配有专门的网站,用以进行实例展示和问题答疑。

作为一本CSS进阶书,本书非常适合有一定CSS基础的前端开发人员学习和参考。


“CSS世界三部曲”分别是《CSS世界》《CSS选择器世界》和《CSS新世界》,本书是其中的第二部。本书的出版距离第一部《CSS世界》出版近两年时间,在这近两年时间中,CSS选择器Level 4规范逐渐稳定,并且很多很棒的特性已经可以在实际项目中应用。我觉得时机成熟了,是时候把CSS选择器世界的精彩内容梳理一番呈现给大家了。

CSS选择器是CSS世界的支柱,撑起了整个精彩纷呈的CSS世界,作为“CSS世界三部曲”的中间一部的主题再合适不过了,承上启下,贯穿所有。

本书里面有什么?有干货。

我专注于CSS领域已经十多年了。很多人觉得很奇怪,CSS有什么好研究的。怎么说呢?就好比,河水流动、苹果下落,这些虽然看起来都是理所当然的现象,没什么好研究的,但实际上,一旦深入,就可以从这些简单现象中发现新的世界。

然而,发现与探索的过程是艰辛的,往往会付出很多,但发现很少,需要有足够的热爱以及钻研精神才能坚持下去并有所收获。恰好,我就是这种类型的人,我喜爱技术研究,喜欢做这种看起来吃力不讨好的事情,但这些年的坚持也让我有了足够的积累。本书的内容就是我根据这些年研究总结出来的精华、经验和技巧,也就是说,大家只要花几小时捧起这本书,就能学到我花费几年的时间提炼出来的东西,这些东西就是所谓的“干货”,它们是技术文档和技术手册上没有的,是稀缺且独一无二的。

而这些稀缺的“干货”,就是你和普通CSS开发人员的技术分水岭,也是你未来的竞争力所在。行业里有一拨儿人,也自称前端,但是只停留在可以根据设计稿写出页面这种水平,这种程度的人没有技术优势,一旦年龄和体力跟不上,将很容易被行业淘汰,因此你需要的不是浮于表面的那一点知识,而是更有深度、与用户体验走得更近的干货和技能。这些就是本书能提供给你的。

这是一本CSS进阶书,非常适合有一定CSS基础的前端人员学习和参考,新手读起来会有些吃力,因为为了做到内容精练,书中会直接略去过于基础的知识。

本书融入了大量我的个人理解,这些理解是我多年持之以恒对CSS进行研究和思考后,经过个人情感润饰和认知提炼获得的产物。因此,与干巴巴的教条式的技术书相比,本书要显得更易于理解,有温度,更有人文关怀。但是,个人的理解并不能保证百分之百正确,因此,本书的个别观点也可能不对,欢迎读者提出质疑和挑战。

由于规范尚未定稿,本书部分比较前沿的知识点在未来会发生某些小的变动,我会实时跟进,并在官方论坛同步更新。

我专门为“CSS世界三部曲”制作了一个网站(https://www.cssworld.cn),在那里,读者可以了解更多“CSS世界三部曲”的相关信息。如果读者有质疑,想挑战,或者要纠错,都欢迎去官方论坛(https://bbs.cssworld.cn/)对应版块进行提问或反馈,也欢迎读者加微信zhangxinxu-job和我直接沟通交流。


衷心感谢人民邮电出版社的每一个人。

感谢人民邮电出版社的编辑杨海玲,她的专业建议对我帮助很大,她对细节的关注令人印象深刻,她使我的工作变得更加轻松。

感谢那些为提高整个行业CSS水平而默默努力的优秀人士,感谢那些在我成长路上指出错误的前端同仁,让我在探索边界的道路上走得更快、更踏实。

感谢读者,你们的支持给了我工作的动力。

最后,最最感谢我的妻子丹丹,没有她在背后的爱和支持,本书一定不会完成得这么顺利。


本书由异步社区出品,社区(https://www.epubit.com/)为您提供后续服务。

作者和编辑尽最大努力来确保书中内容的准确性,但难免会存在疏漏。欢迎您将发现的问题反馈给我们,帮助我们提升图书的质量。

当您发现错误时,请登录异步社区,按书名搜索,进入本书页面,单击“提交勘误”,输入勘误信息,单击“提交”按钮即可(见下图)。本书的作者和编辑会对您提交的勘误进行审核,确认并接受后,您将获赠异步社区的100积分。积分可用于在异步社区兑换优惠券、样书或奖品。

我们的联系邮箱是contact@epubit.com.cn。

如果您对本书有任何疑问或建议,请您发邮件给我们,并请在邮件标题中注明本书书名,以便我们更高效地做出反馈。

如果您有兴趣出版图书、录制教学视频,或者参与图书翻译、技术审校等工作,可以发邮件给我们;有意出版图书的作者也可以到异步社区在线提交投稿(直接访问www.epubit.com/ selfpublish/submission即可)。

如果您来自学校、培训机构或企业,想批量购买本书或异步社区出版的其他图书,也可以发邮件给我们。

如果您在网上发现有针对异步社区出品图书的各种形式的盗版行为,包括对图书全部或部分内容的非授权传播,请您将怀疑有侵权行为的链接发邮件给我们。您的这一举动是对作者权益的保护,也是我们持续为您提供有价值的内容的动力之源。

“异步社区”是人民邮电出版社旗下IT专业图书社区,致力于出版精品IT技术图书和相关学习产品,为作译者提供优质出版服务。异步社区创办于2015年8月,提供大量精品IT技术图书和电子书,以及高品质技术文章和视频课程。更多详情请访问异步社区官网https://www.epubit.com。

“异步图书”是由异步社区编辑团队策划出版的精品IT专业图书的品牌,依托于人民邮电出版社近30年的计算机图书出版积累和专业编辑团队,相关图书在封面上印有异步图书的LOGO。异步图书的出版领域包括软件开发、大数据、AI、测试、前端、网络技术等。

异步社区

微信服务号


CSS选择器本身很简单,就是一些特定的选择符号,于是,很多开发者就认为CSS选择器的世界很简单,没什么好学的,这样的想法严重限制了开发者的技术提升。实际上,CSS选择器非常强大,它不仅涉及视觉表现,而且与用户安全、用户体验有非常密切的联系。

CSS选择器能够做的事情远比你预想的多得多。

不少开发人员学习JavaScript得心应手,但是学习CSS却总是没有感觉,因为他们还是习惯把CSS属性或者CSS选择器看成一个个独立的个体,就好像传统编程语言中的一个个API一样。传统编程语言讲求逻辑清晰,层次分明,主要为功能服务,因此这种不拖泥带水的API是非常有必要的。但CSS却是为样式服务的,它重表现,轻逻辑,如同人的思想一样,相互碰撞才能产生火花。

尤其对于CSS选择器,它作为CSS世界的支柱,其作用好比人类的脊柱,与HTML结构、浏览器行为、用户行为以及整个CSS世界相互依存、相互作用,这必然会产生很多碰撞,让CSS选择器变得非常强悍。

同时,CSS选择器本身也并非你想得那么单纯。

我们平常所说的CSS选择器实际上是一个统称,是很多基本概念的集合,在正式开始介绍本书的内容之前,我们有必要先了解一下这些基本概念。

CSS选择器可以分为4类,即选择器、选择符、伪类和伪元素。

1.选择器

这里的“选择器”指的就是平常使用的CSS声明块前面的标签、类名等。例如:

body { font: menu; }

这里的body就是一种选择器,是类型选择器,也可以称为标签选择器。

.container { background-color: olive; }

这里的.container也是选择器,属于属性选择器的一种,我们平时称其为类选择器。

还有很多其他种类的选择器,后面将会详细介绍。

2.选择符

目前我所知道的CSS选择器世界中的选择符有5个,即表示后代关系的空格( ),表示父子关系的尖括号(>),表示相邻兄弟关系的加号(+),表示兄弟关系的弯弯(~),以及表示列关系的双管道(||)。

这5种选择符分别示意如下:

/* 后代关系 */
.container img { object-fit: cover; }
/* 父子关系 */
ol > li { margin: .5em 0; }
/* 相邻兄弟关系 */
button + button { margin-left: 10px; }
/* 兄弟关系 */
button ~ button { margin-left: 10px; }
/* 列 */
.col || td { background-color: skyblue; }

关于选择符的更多知识可以参见第4章。

3.伪类

伪类的特征是其前面会有一个冒号(:),通常与浏览器行为和用户行为相关联,可以看成是CSS世界的JavaScript。伪类和选择符相互配合可以实现非常多的纯CSS交互效果。

例如:

a:hover { color: darkblue; }

4.伪元素

伪元素的特征是其前面会有两个冒号(::),常见的有::before::after::first- letter::first-line等。

本书不会对伪元素做专门的介绍,读者若有兴趣可以参见《CSS世界》和以后会出版的《CSS新世界》的相关章节。

以前CSS选择器只有一个全局作用域,也就是在网页任意地方的CSS都共用一个文档上下文。

如今CSS选择器是有局部作用域的概念的。伪类:scope的设计初衷就是匹配局部作用域下的元素。例如,对于下面的代码:

<section>
  <style scoped>
   p { color: blue; } 
   :scope { background-color: red; }
  </style>
  <p>在作用域内,背景色应该红色。</p>
</section>
<p>在作用域外,默认背景色。</p>

理论上,<section>标签里面的<p>元素的背景色应该是红色,但目前没有任何浏览器表现为红色。实际上此特性曾被浏览器支持过,但只是昙花一现,现在已经被舍弃。目前虽然伪类:scope也能解析,但只能当作全局作用域。但是,这并不表示:scope一无是处,它在JavaScript中还是有效的,这一点将在12.1.1节中进一步展开介绍。

另外,CSS选择器的局部作用域在Shadow DOM中也是有效的。例如,有一个<div>元素:

<div id="hostElement"></div>

然后使用Shadow DOM为这个<div>元素创建一个<p>元素并且控制其背景色的样式,如下:

// 创建Shadow DOM
var shadow = hostElement.attachShadow({mode: 'open'});
// 给Shadow DOM添加文字
shadow.innerHTML = '<p>我是由Shadow DOM创建的&lt;p&gt;元素,我的背景色是?</p>';
// 添加CSS,p标签背景色变成黑色
shadow.innerHTML += '<style>p { background-color: #333; color: #fff; }</style>';

结果如图1-1所示,Shadow DOM创建的<p>元素的背景色是黑色,而页面原本的<p>元素的背景色不受任何影响。

图1-1 页面原本的<p>元素的背景色不受任何影响

上面的CSS选择器的局部作用示例都配有演示页面,读者可以手动输入https://demo.cssworld. cn/selector/1/2-1.php或扫描下面的二维码亲自体验与学习。

CSS选择器中还有一个命名空间(namespace)的概念,这里简单介绍一下。

命名空间可以让来自多个XML词汇表的元素的属性或样式彼此之间没有冲突,它的使用非常常见,例如XHTML文档:

<html xmlns="http://www.w3.org/1999/xhtml">

又例如SVG文件的命名空间:

<svg xmlns="http://www.w3.org/2000/svg">

上述代码中的xmlns属性值对应的URL地址就是一个简单的命名空间名称,其并不指向实际的在线地址,浏览器不会使用或处理这个URL。

在CSS选择器世界中命名空间的作用也是避免冲突。例如,在HTML和SVG中都会用到<a>链接,此时就可能发生冲突,我们可以借助命名空间进行规避,具体方法是,使用@namespace规则声明命名空间:

@namespace url(http://www.w3.org/1999/xhtml);
@namespace svg url(http://www.w3.org/2000/svg);
/* XHTML中的<a>元素 */
a {}
/* SVG中<a>元素 */
svg|a {}
/* 同时匹配XHTML和SVG的<a>元素 */
*|a {}

注意,上述CSS代码中的svg也可以换成其他字符,这里的svg并不是表示svg标签的意思。

眼见为实,我们通过一个实际案例来直观地了解一下CSS选择器的命名空间。HTML和CSS代码如下:

<p>这是文字:<a href>点击刷新</a></p>
<p>这是SVG:<svg><a xlink:href><path d="..."/></a></svg></p>
@namespace "http://www.w3.org/1999/xhtml";
@namespace svg "http://www.w3.org/2000/svg";
svg|a { color: black; fill: currentColor; }
a { color: gray; }

svg|a中有一个管道符|,管道符前面的字符表示命名空间的代称,管道符后面的内容则是选择器。本例的代码表示在http://www.w3.org/2000/svg这个命名空间下所有<a>的颜色都是black,由于xhtml的命名空间也被指定了,因此SVG中的<a>就不会受标签选择器a的影响,即便纯标签选择器a的优先级再高也无效。

最终的效果如图1-2所示,文字链接颜色为灰色,SVG图标颜色为黑色。

图1-2 不同命名空间下的样式保护

眼见为实,读者可以手动输入https://demo.cssworld.cn/selector/1/2-2.php或扫描下面的二维码亲自体验与学习。

CSS选择器命名空间的兼容性很好,至少10年前浏览器就已支持,但是,却很少见人在项目中使用它,这是为什么呢?

原因有二:其一,在HTML中直接内联SVG的应用场景并不多,它更多的是作为独立的SVG资源使用,即使内联,也很少有需要对特性SVG标签进行样式控制的需求;其二,有其他更简单的替代方案,例如,如果我们希望SVG中所有的<a>元素的颜色都是black,可以直接用:

svg a { color: black; }

无须掌握复杂的命名空间语法就能实现我们想要的效果,这样做的唯一缺点就是增加了SVG中a元素的优先级,但是在大多数场景下,这对我们的实际开发没有任何影响。综合来看,这是一种性价比高很多的实现方式,几乎找不到需要使用命名空间的理由。

因此,对于CSS选择器的命名空间,我给大家的建议就是了解即可,做到在遇到大规模冲突场景时,能想到还有这样一种解决方法就可以了。

很多CSS伪类选择器是最近几年才出现的,浏览器并不支持,浏览器会把这些选择器当作无效选择器,这是没有任何问题的。但是当这些无效的CSS选择器和浏览器支持的CSS选择器写在一起的时候,会导致整个选择器无效,举个例子,有如下CSS代码:

.example:hover,
.example:active,
.example:focus-within {
   color: red;
}

:hover:active是浏览器很早就支持的两个伪类,按道理讲,所有浏览器都能识别这两个伪类,但是,由于IE浏览器并不支持:focus-within伪类,会导致IE浏览器无法识别整个语句,这就是无效CSS选择器特性。

因此,我们在使用一些新的CSS选择器时,出于渐进增强的目的,需要将它们分开书写:

/* IE浏览器可识别 */
.example:hover,
.example:active {
   color: red;
}
/* IE浏览器不可识别 */
.example:focus-within {
   color: red;
}

不过,在诸多CSS选择器中,这种无效选择器特性出现了一个例外,那就是浏览器可以识别以-webkit-私有前缀开头的伪元素。例如,下面这段CSS选择器就是无效的:

div, span::whatever {
  background: gray;
}

但是,如果加上一个-webkit-私有前缀,浏览器就可以识别了,<div>元素背景为灰色,如图1-3所示:

div, span::-webkit-whatever {
  background: gray;
}

图1-3 div背景为gray

除了IE浏览器,其他浏览器均支持(Firefox 63及以上版本支持)识别这个-webkit-无效伪元素的特性。于是,我们就可以灵活运用这种特性来帮助完成实际开发。例如,对IE浏览器和其他浏览器进行精准区分:

/* IE浏览器 */
.example {
  background: black;
}
/* 其他浏览器 */
.example, ::-webkit-whatever {
  background: gray;
}

当然,上面的无效伪类会导致整行选择器失效的特性也可以用来区分浏览器。


几乎所有的CSS样式冲突、样式覆盖等问题都与CSS声明的优先级错位有关。因此,在详细阐述CSS选择器的优先级规则之前,我们先快速了解一下CSS全部的优先级规则。

CSS优先级有着明显的不可逾越的等级制度,我将其划分为0~5这6个等级,其中前4个等级由CSS选择器决定,后2个等级由书写形式和特定语法决定。下面我将对这6个等级分别进行讲解。

(1)0级:通配选择器、选择符和逻辑组合伪类。其中,通配选择器写作星号(*)。示例如下:

* { color: #000; }

选择符指+>~、空格和||。关于选择符的更多知识可参见第4章。

逻辑组合伪类有:not()、:is()和:where等,这些伪类本身并不影响CSS优先级,影响优先级的是括号里面的选择器。

:not() {}

需要注意的是,只有逻辑组合伪类的优先级是0,其他伪类的优先级并不是这样的。

(2)1级:标签选择器。示例如下:

body { color: #333; }

(3)2级:类选择器、属性选择器和伪类。示例如下:

.foo { color: #666; }
[foo] { color: #666; }
:hover { color: #333; }

(4)3级:ID选择器。示例如下:

#foo { color: #999; }

(5)4级:style属性内联。示例如下:

<span style="color: #ccc;">优先级</span>

(6)5级:!important。示例如下:

.foo { color: #fff !important; }

!important是顶级优先级,可以重置JavaScript设置的样式,唯一推荐使用的场景就是使JavaScript设置无效。例如:

.foo[style*="color: #ccc"] { 
  color: #fff !important;
}

对于其他场景,没有任何使用它的理由,切勿滥用。

不难看出,CSS选择器的优先级(0级至3级)属于CSS优先级的一部分,也是最重要、最复杂的部分,学会CSS选择器的优先级等同于学会了完整的CSS优先级规则。

本节内容将有助于深入理解CSS选择器的优先级,包括计算规则、实用技巧以及一些奇怪的有趣特性。

对于CSS选择器优先级的计算,业界流传甚广的是数值计数法。具体如下:每一段CSS语句的选择器都可以对应一个具体的数值,数值越大优先级越高,其中的CSS语句将被优先渲染。其中,出现一个0级选择器,优先级数值+0;出现一个1级选择器,优先级数值+1;出现一个2级选择器,优先级数值+10;出现一个3级选择器,优先级数值+100。

于是,有表2-1所示的计算结果。

表2-1 选择器优先级计算值

选择器

计算值

计算细则

* {}

0

1个0级通配选择器,优先级数值为0

dialog {}

1

1个1级标签选择器,优先级数值为1

ul > li {}

2

2个1级标签选择器,1个0级选择符,优先级数值为1+0+1

li > ol + ol {}

3

3个1级标签选择器,2个0级选择符,优先级数值为

1+0+1+0+1

 

 

.foo {}

10

1个2级类名选择器,优先级数值为10

a:not([rel=nofollow]) {}

11

1个1级标签选择器,1个0级否定伪类,1个2级属性选择器,优先级数值为1+0+10

a:hover {}

11

1个1级标签选择器,1个2级伪类,优先级数值为1+10

ol li.foo {}

12

1个2级类名选择器,2个1级标签选择器,1个0级空格选择符,优先级数值为1+0+1+10

li.foo.bar {}

21

2个2级类名选择器,1个1级标签选择器,优先级数值为10×2+1

#foo {}

100

1个3级ID选择器,优先级数值为100

#foo .bar p {}

111

1个3级ID选择器,1个2级类名选择器,1个1级标签选择器,优先级数值为100+10+11

趁热打铁,我出一个小题考考大家,<body>元素的颜色是红色还是蓝色?

<html lang="zh-CN">
   <body class="foo">颜色是?</body>
</html>
body.foo:not([dir]) { color: red; }
html[lang] > .foo { color: blue; }

我们先来计算一下各自的优先级数值。

首先是body.foo:not([dir]),出现了1个标签选择器body,1个类名选择器.foo和1个否定伪类:not,以及属性选择器[dir],计算结果是1+10+0+10,也就是21。

接下来是html[lang] > body.foo,出现了1个标签选择器html,1个属性选择器[lang]和1个类名选择器.foo,计算结果是1+10+10,也就是21。

这两个选择器的计算值居然是一样的,那该怎么渲染呢?

这就引出了另外一个重要的规则——“后来居上”。也就是说,当CSS选择器的优先级数值一样的时候,后渲染的选择器的优先级更高。因此,上题的最终颜色是蓝色(blue)

后渲染优先级更高的规则是相对于整个页面文档而言的,而不仅仅是在一个单独的CSS文件中。例如:

<style>body { color: red; }</style>
<link rel="stylesheet" href="a.css">
<link rel="stylesheet" href="b.css">

其中在a.css中有:

body { color: yellow; }

在b.css中有:

body { color: blue; }

此时,body的颜色是蓝色,如图2-1所示,因为blue这段CSS语句在文档中是最后出现的。

图2-1 浏览器中body颜色的优先级

还有一个误区有必要强调一下,那就是CSS选择器的优先级与DOM元素的层级位置没有任何关系。例如:

body .foo { color: red; }
html .foo { color: blue; }

请问.foo的颜色是红色还是蓝色?

答案是蓝色。虽然<body><html>的子元素,离.foo的距离更近,但是选择器的优先级并不考虑DOM的位置,所以后面的html.foo{}的优先级更高。

1.增加CSS选择器优先级的小技巧

实际开发时,难免会遇到需要增加CSS选择器优先级的场景。例如,希望增加下面.foo类名选择器的权重:

.foo { color: #333; }

很多人的做法是增加嵌套,例如:

.father .foo {}

或者是增加一个标签选择器,例如:

div.foo {}

但这些都不是最好的方法,因为这些方法增加了耦合,降低了可维护性,一旦哪天父元素类名变化了,或者标签换了,样式岂不是就失效了?这里给大家介绍一个增加CSS选择器优先级的小技巧,那就是重复选择器自身。例如,可以像下面这样做,既提高了优先级,又不会增加耦合,实在是上上之选:

.foo.foo {}

如果你实在不喜欢这种写法,借助必然会存在的属性选择器也是不错的方法。例如:

.foo[class] {}
#foo[id] {}

2.对数值计数法的点评

上面提到的CSS选择器优先级数值的计数法实际上是一个不严谨的方法,因为1和10之间的差距实在太小了,这也就意味着连续10个标签选择器的优先级就和1个类名选择器齐平了。然而事实并非如此,不同等级的选择器之间的差距是无法跨越的存在。但由于在实际开发中,我们是不会连续写上多达10个选择器的,因此不会影响我们在实际开发过程中计算选择器优先级。

而且对于使用CSS选择器而言,你的书写习惯远比知识更重要,就算你理论知识再扎实,如果平时书写习惯糟糕,也无法避免CSS样式覆盖问题、样式冲突等问题的出现。我将在第3章中深入探讨这个问题。因此,对于数值计算法,我的态度是,学一遍即可,没有必要反复攻读,做到面面俱到,只要你习惯足够好,是不会遇到乱七八糟的优先级问题的。

在CSS选择器这里,等级真的是无法跨越的鸿沟吗?其实不是,这里有大家不知道的冷知识。

有如下HTML:

<span id="foo" class="f">颜色是?</span>

如下CSS:

#foo { color: #000; background: #eee; }
.f { color: #fff; background: #333; }

很显然,文字的颜色是#000,即黑色,因为ID选择器的级别比类名选择器的级别高一级。但是,如果是下面的CSS呢?256个.f类名合体:

#foo { padding: 10px 20px; color: #000; background: #eee; }
.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f { color: #fff; background: #333; }

在IE浏览器下,神奇的事情发生了,文字的颜色表现为白色,背景色表现为深色,如图2-2所示。

图2-2 IE浏览器中类名的优先级更高

在IE浏览器下,读者可以输入https://demo.cssworld.cn/selector/2/2-1.php亲自体验与学习。

同样,256个标签选择器的优先级大于类名选择器的优先级的现象也是存在的。

实际上,在过去,Chrome浏览器、Firefox浏览器下都出现过这种256个选择器的优先级大于上一个选择器级别的现象,后来,大约2015年之后,Chrome浏览器和Firefox浏览器都修改了策略,使得再多的选择器的优先级也无法超过上一级,因此,目前越级现象仅在IE浏览器中可见。

为什么会有这种有趣的现象呢?早些年查看Firefox浏览器的源代码,发现所有的类名都是以8字节字符串存储的,8字节所能容纳的最大值就是255,因此同时出现256个类名的时候, 势必会越过其边缘,溢出到ID区域。而现在采用了16字节的字符串存储,能容纳的类型数量足够多了,就不会出现这种现象。

当然,这个冷知识并没有多大的实用价值,大致了解一下即可。

了解了CSS选择器的优先级之后,很多日常工作中遇到的一些问题你就知道是怎么回事了,举一个按钮:hover变色的例子。

例如,我们写一个蓝底白字的按钮,使鼠标经过按钮时会改变背景色:

.cs-button {
   background-color: darkblue;
   color: white;
}
.cs-button:hover {
   background-color: blue;
}
<a href="javascript:" class="cs-button" role="button">按钮</a>

看代码没有任何问题,但是页面一刷新就出现问题了。鼠标经过按钮的时候,文字居然变成蓝色了,而不是预期的白色!

究竟是哪里出了问题呢?一排查,这个问题居然是CSS reset导致的。

在实际开发中,我们一定会对全局的链接颜色进行设置,例如,按钮默认颜色为蓝色,鼠标经过的时候变成深蓝色:

a { color: blue; }
a:hover { color: darkblue; }

按钮变色就是这里的a:hover导致的。因为a:hover的优先级比.cs-button的优先级高(:hover伪类的优先级和类选择器的优先级一样),所以鼠标经过按钮的时候按钮颜色表现为a:hover设置的深蓝色。

知道原因,问题就好解决了,常见做法是再设置一遍鼠标经过按钮的颜色:

.cs-button:hover {
   color: white;
   background-color: blue;
}

或者按钮改用语义更好的button标签,而不是传统的a标签。


相关图书

CSS选择器世界(第2版)
CSS选择器世界(第2版)
HTML+CSS+JavaScript完全自学教程
HTML+CSS+JavaScript完全自学教程
零基础入门学习Web开发(HTML5 & CSS3)
零基础入门学习Web开发(HTML5 & CSS3)
CSS新世界
CSS新世界
HTML CSS JavaScript入门经典 第3版
HTML CSS JavaScript入门经典 第3版
HTML+CSS+JavaScript网页制作 从入门到精通
HTML+CSS+JavaScript网页制作 从入门到精通

相关文章

相关课程