CSS选择器世界(txt+pdf+epub+mobi电子书下载)


发布时间:2020-06-03 00:03:09

点击下载

作者:张鑫旭

出版社:人民邮电出版社有限公司

格式: AZW3, DOCX, EPUB, MOBI, PDF, TXT

CSS选择器世界

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世界》出版近两年时间,在这近两年时间中,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、测试、前端、网络技术等。异步社区微信服务号第1章 概述

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

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

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

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

同时,CSS选择器本身也并非你想得那么单纯。1.2 CSS选择器世界的一些基本概念

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

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新世界》的相关章节。1.2.2 CSS选择器的作用域

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

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

在作用域内,背景色应该红色。

在作用域外,默认背景色。

理论上,

标签里面的

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

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

元素:

然后使用Shadow DOM为这个

元素创建一个

元素并且控制其背景色的样式,如下:// 创建Shadow DOMvar shadow = hostElement.attachShadow({mode: 'open'});// 给Shadow DOM添加文字shadow.innerHTML = '

我是由Shadow DOM创建的<p>元素,我的背景色是?

';// 添加CSS,p标签背景色变成黑色shadow.innerHTML += '';

结果如图1-1所示,Shadow DOM创建的

元素的背景色是黑色,而页面原本的

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

元素的背景色不受任何影响

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

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

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

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

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

在CSS选择器世界中命名空间的作用也是避免冲突。例如,在HTML和SVG中都会用到链接,此时就可能发生冲突,我们可以借助命名空间进行规避,具体方法是,使用@namespace规则声明命名空间:@namespace url(http://www.w3.org/1999/xhtml);@namespace svg url(http://www.w3.org/2000/svg);/* XHTML中的元素 */a {}/* SVG中元素 */svg|a {}/* 同时匹配XHTML和SVG的元素 */*|a {}

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

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

这是文字:点击刷新

这是SVG:

@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这个命名空间下所有的颜色都是black,由于xhtml的命名空间也被指定了,因此SVG中的就不会受标签选择器a的影响,即便纯标签选择器a的优先级再高也无效。

最终的效果如图1-2所示,文字链接颜色为灰色,SVG图标颜色为黑色。图1-2 不同命名空间下的样式保护

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

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

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

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

因此,对于CSS选择器的命名空间,我给大家的建议就是了解即可,做到在遇到大规模冲突场景时,能想到还有这样一种解决方法就可以了。1.3 无效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-私有前缀,浏览器就可以识别了,

元素背景为灰色,如图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;}

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

几乎所有的CSS样式冲突、样式覆盖等问题都与CSS声明的优先级错位有关。因此,在详细阐述CSS选择器的优先级规则之前,我们先快速了解一下CSS全部的优先级规则。2.1 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属性内联。示例如下:优先级(6)5级:!important。示例如下:.foo { color: #fff !important; }

!important是顶级优先级,可以重置JavaScript设置的样式,唯一推荐使用的场景就是使JavaScript设置无效。例如:.foo[style*="color: #ccc"] { color: #fff !important;}

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

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

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

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

于是,有表2-1所示的计算结果。表2-1 选择器优先级计算值选择器计算计算细则值* {}01个0级通配选择器,优先级数值为0dialog {}11个1级标签选择器,优先级数值为1ul > li {}22个1级标签选择器,1个0级选择符,优先级数值为1+0+1li > ol + ol {}33个1级标签选择器,2个0级选择符,优先级数值为1+0+1+0+1  .foo {}101个2级类名选择器,优先级数值为10a:111个1级标签选择器,1个0级否定伪类,1个2级属性选择器,not([rel=nofollo优先级数值为1+0+10w]) {}a:hover {}111个1级标签选择器,1个2级伪类,优先级数值为1+10ol li.foo {}121个2级类名选择器,2个1级标签选择器,1个0级空格选择符,优先级数值为1+0+1+10li.foo.bar {}212个2级类名选择器,1个1级标签选择器,优先级数值为10×2+1#foo {}1001个3级ID选择器,优先级数值为100#foo .bar p {}1111个3级ID选择器,1个2级类名选择器,1个1级标签选择器,优先级数值为100+10+11

趁热打铁,我出一个小题考考大家,元素的颜色是红色还是蓝色? 颜色是?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文件中。例如:

其中在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的颜色是红色还是蓝色?

答案是蓝色。虽然是的子元素,离.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选择器这里,等级真的是无法跨越的鸿沟吗?其实不是,这里有大家不知道的冷知识。2.2.2 256个选择器的越级现象

有如下HTML:颜色是?

如下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字节的字符串存储,能容纳的类型数量足够多了,就不会出现这种现象。

当然,这个冷知识并没有多大的实用价值,大致了解一下即可。2.3 为什么按钮:hover变色了

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

例如,我们写一个蓝底白字的按钮,使鼠标经过按钮时会改变背景色:.cs-button { background-color: darkblue; color: white;}.cs-button:hover { background-color: blue;}按钮

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

究竟是哪里出了问题呢?一排查,这个问题居然是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标签。第3章 CSS选择器的命名

CSS选择器的命名问题是最常困扰开发者的事情之一。究竟是面向CSS属性命名,还是面向HTML语义命名?是使用长命名,还是使用短命名?这些疑问在本章都能找到答案,并且我还会把一些多年摸索出来的最佳实践分享给读者。

在此之前,我们不妨先了解一些关于CSS选择器的基础特性。3.1 CSS选择器是否区分大小写

CSS选择器有些区分大小写,有些不区分大小写,还有些可以设置为不区分。

要搞清楚CSS选择器是否区分大小写的问题,还要从HTML说起。在HTML中,标签和属性都是不区分大小写的,而属性值是区分大小写的。于是,相对应地,在CSS中,标签选择器不区分大小写,属性选择器中的属性也不区分大小写,而类选择器和ID选择器本质上是属性值,因此要区分大小写。

下面我们通过一个例子来一探究竟。HTML如下:

颜色是?

CSS如下:P { padding: 10px; background-color: black; }[CLASS] { color: white; }.CONTENT { text-decoration: line-through; }

HTML字符全部都是小写,3种类型的CSS选择器均使用大写,结果如图3-1所示,黑底白字无贯穿线,这说明选择器P和选择器[CLASS]生效,而.CONTENT无效。图3-1 CONTENT类名没有匹配,导致贯穿线没有生效

选择器对大小写敏感情况的总结见表3-1。表3-1 选择器对大小写的敏感情况选择器类型示例是否对大小写敏感标签选择器div {}不敏感属性选择器-纯属性[attr]不敏感属性选择器[attr=val]属性值敏感类选择器.container {}敏感ID选择器#container {}敏感

然而,随着各大浏览器支持属性选择器中的属性值也不区分大小写(在]前面加一个i),已经没有严格意义上的对大小写敏感的选择器了,因为类选择器和ID选择器本质上也是属性选择器,因此,如果希望HTML中的类名对大小写不敏感,可以这样:[class~="val" i] {}

例如:

颜色是?

CSS如下:P { padding: 10px; background-color: black; }[CLASS] { color: white; }[CLASS~=CONTENT i] { text-decoration: line-through; }

结果如图3-2所示,黑底白字贯穿线,说明上面3个选择器均对大小写不敏感。图3-2 CONTENT类名作为属性值可以匹配,使贯穿生效

更多关于属性选择器大小写敏感的内容参见第6章。3.2 CSS选择器命名的合法性

这里主要讲一下类选择器和ID选择器的命名合法性问题,旨在纠正大家长久以来的错误认识。什么错误认识呢?最常见的就是类名选择器和ID选择器不能以数字开头,如下:.1-foo { border: 10px dashed; padding: 10px; } /* 无效 */

对,上面这种写法确实无效,但这并不是因为不能以数字开头,而是不能直接写数字,需要将其转义一下,如下:.\31 -foo { border: 10px dashed; padding: 10px; }

此时,下面的HTML就表现为黑底白字:颜色是?

效果如图3-3所示,所有浏览器下均有虚线边框。图3-3 以数字开头的类选择器生效了

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

为什么会有这么奇怪的表示?居然表示成\31,而且后面还有一个空格!

其实\31外加空格是CSS中字符1的十六进制转码表示。其中31就是字符1的Unicode值,如下:console.log('1'.charCodeAt().toString(16)); // 结果是31

字符0的Unicode值是30,字符9的Unicode值是39,0~9这10个数字对应的Unicode值正好是30~39。

我们也可以用以下这种方法进行表示:.\000031-foo { border: 10px dashed; padding: 10px; }

31前面用4个0进行补全,这样\31后面就不用加空格。

类名或者ID甚至可以是纯数字,例如下面的代码CSS也能渲染:请问:颜色是?.\31 { border: 10px dashed; padding: 10px; }

如果选择器中有父子关系,则需要打两个空格:.\31 em { margin-right: 10px; }

然而,CSS压缩工具会乱压空格,所以,实际开发时,如果想使用数字,建议使用非空格完整表示法:.\000031 em { margin-right: 10px; }规范与更多字符的合法性

顺着上面这个“不能以数字开头”的案例,我们可以讲更多关于选择器命名合法性的内容。

首先,关于命名,看看规范是怎么说的,如图3-4所示。图3-4 规范中对选择器命名的描述

图3-4明显分左右两半,其中左边是选择器首字符,右边是选择器后面的字符。从图中可以清晰地看到,首字符支持的字符类型是a~z、A~Z、下划线(_)以及非ASCII字符(中文、全角字符等),后面的字符支持的字符类型是a~z、A~Z、0~9、下划线(_)、短横线(-)以及非ASCII字符,后面的字符支持的字符类型多了数字和短横线。

很多人对选择器的合法性认识就停留在上面的内容,而忽略了图3-4下面的“escape”方块。也就是说,对于其他没有出现的字符,只要对它们执行转义重新编码一下也能使其成为支持的字符类型。

也就是说,选择器不仅可以以数字开头,也支持以其他字符开头。这些字符可以是下面的这些。(1)不合法的ASCII字符,如!、"、#、$、%、&;、'、(、)、*、+、,、-、.、/、:、;、<、=、>、?、@、[、\、]、^、`、{、|、}以及~。

严格来讲,上述字符也应该完全转码。例如,加号(+)的Unicode值是2b,因此选择器需要写成\2b 空格,或者\00002b。

但是,对于上述字符,还有一种更优雅的表示方式,那就是直接使用斜杠转义。示意如下:.\+foo { color: red; }

其他字符也可以这样:.\-foo { color: red; }.\|foo { color: red; }.\,foo { color: red; }.\'foo { color: red; }.\:foo { color: red; }.\*foo { color: red; }...

包括IE在内的浏览器都支持上面的斜杠转义写法,因此可以放心使用。唯一需要多提一句的就是冒号(:),在IE7浏览器下,直接使用\:是不被支持的,如果你的项目需要兼容这些浏览器,可以使用\3a加上空格代替。(2)中文字符。下面的CSS也是有效的:.我是foo { color: red; }(3)中文标点符号,例如:.。foo { color: red; }(4)emoji表情:.☺ { color: red; }

由于emoji字符在手机设备或者OS X系统上自动显示为emoji表情,因此有人会在实验性质的项目中使用emoji字符作为类名,这样,展示源代码的时候,会有一个一个的表情出现,这也挺有意思的。

至于其他转义字符,没有任何在实际项目中使用它们的理由。但我个人觉得中文命名可以一试,毕竟它的可读性更好,命名也更轻松,不需要去找翻译。

到此就结束了吗?还没有。

不知道大家有没有注意到图3-4中还有两个小圆框,其中一个里面是一根短横线(-),还有一个里面是连续两根短横线(--),它们是什么意思呢?

意思是,我们可以直接以短横线开头,如果是一根短横线(-),那么短橫线后面必须有其他字符、字母或下划线或者其他编码字符;如果是连续两根短横线(--),则它的后面不跟任何字符也是合法的。因此,下面两个CSS语句都是合法的,都可以渲染:.-- { color: red; } /* 有效 */.-a-b- { color: red; } /* 有效 */

对于一些需要特殊标记的元素,可以试试以短横线开头命名,它一定会令人印象深刻。3.3 CSS选择器的命名是一个哲学问题

如果你正在参与的是一个独自开发、页面简单且上线几天就寿终正寝的小项目,则你可以完全放飞自我,CSS选择器可以随便命名,中文、emoji字符、各种高级选择器都可以用起来。但是,如果你正在开发多人协作,需要不断迭代、不断维护的项目,则一定要谨慎设计,考虑周全,以职业的态度面对命名这件事情。

自然,开发人员并不傻,也知道对于有些项目,要尽心尽力,他们会发挥出自己的巅峰实力,项目上线后也自我感觉良好。但那些自我感觉良好的开发人员写的CSS代码实际上往往质量堪忧,但开发人员却压根没意识到这个问题,最典型的就是CSS命名的设计很糟糕,他们早已经埋下巨大的隐患却浑然不知。

这样的现象太多了,真的太多了。正因为如此,我觉得有必要好好和大家聊聊CSS选择器命名的问题,先把选择器的CSS代码质量给提升上去。3.3.1 长命名还是短命名

对于使用长命名还是短命名的问题,我的回答是请使用短命名。例如,一段介绍,类名可以这样:.some-intro { line-height: 1.75; }

而没有必要这样:.some-introduction { line-height: 1.75; }

后一种方式不仅增加了书写时间,也增加了CSS文件的大小。虽然这样做使语义更加准确了,也确实有一定价值,但价值很有限。要知道,日后维护代码时,人们只会关心这个类名有没有在其他地方使用过?改变、删除这个类名会不会出现问题?至于语义,人们真的不关心。

CSS选择器的语义和HTML的语义是不一样的,前者只是为了方便人的识别,它对于机器而言没有任何区别,因此价值很弱;但是HTML的语义的重要作用是让机器识别,如搜索引擎或者屏幕阅读器等,它是与用户体验与产品价值密切相关的。

因此,请使用短命名,足矣!一旦习惯,或者约定俗成,完全不影响阅读,就好比

标签是paragraph的简写,语义表示段落一样。3.3.2 单命名还是组合命名

单命名的优点是字符少、书写快,缺点是容易出现命名冲突的问题;组合命名的优点是不容易出现命名冲突,但写起来较烦琐。样式冲突的性质比书写速度慢严重得多,因此,理论上推荐使用组合命名,但在实际开发中,项目追求的往往是效益最大化,而不是完美的艺术品。因此,具体该如何取舍,不能一概而论,只能从经验层面进行阐述。(1)对于多人合作、长期维护的项目,千万不要出现下面这些以常见单词命名的单命名选择器,因为后期非常容易出现命名冲突的问题,即使你的项目不会引入第三方的CSS:.title {} /* 不建议 */.text {} /* 不建议 */.box {} /* 不建议 */

这几个命名是出现频率最高的,一定要使用另外的前缀组合将它们保护起来,这个前缀可以是模块名称,或者场景名称,例如:.dialog-title {}.ajax-error-text {}.upload-box {}(2)如果你的项目会使用第三方的UI组件,就算是全站公用的CSS,也不要出现下面这样的单命名,因为说不定下面的命名就会与第三方CSS发生冲突:.header {} /* 不建议 */.main {} /* 不建议 */.aside {} /* 不建议 */.warning {} /* 不建议 */.success {} /* 不建议 */.red {} /* 不建议 */.green {} /* 不建议 */

正确的做法是加一个统一的前缀,使用组合命名的方式。你可以随意命名这个前缀,可以是项目代号的英文缩写,也可以是产品名称的拼音首字母,因为这个前缀的作用是避免冲突,它并不需要任何语义。但需要注意的是前缀最好不要超过4个字母,因为字母多了完全没有任何意义,只会徒增CSS文件的大小。例如,“CSS选择器”的英文是CSS Selector,我就可以取CSS的首字母C和Selector的首字母S作为本书所有选择器的前缀类名,于是有:.cs-header {}.cs-main {}.cs-aside {}...

如果你认真观察所有的开源UI框架,会发现其CSS样式一定都有一个一致的前缀,因为这样做会避免发生冲突,我们自己开发项目的时候也要秉承这个理念。(3)如果你的项目百分百是自主研发的,以后维护此项目的人也不会盗取别人的CSS来充数,则与网站公用结构、颜色相关的这些CSS可以使用单命名,例如:.dark { color: #4c5161; }.red { color: #f4615c; }.gray { color: #a2a9b6; }

但对于非公用内容,如标题(.title)、盒子(.box)等就不能使用单命名,因为颜色这类样式是贯穿于整个项目的,具有高度的一致性,而标题(.title)会在很多地方出现,且样式各不相同,如大标题、小标题、弹框标题、模块标题等,容易产生命名冲突。

对于网站UI组件,各个业务模块一定要采用多名称的组合命名方式,且最好都有一个统一的命名前缀。(4)如果你做的项目并不需要长期维护,也不需要多人合作,例如,只是一些运营活动,请务必添加统一的项目前缀,这都是过来人的忠告,因为这次活动的某些功能和效果日后会被复用,有了统一的前缀,日后直接复制代码就能使用,没有后顾之忧,大家都开心,例如:.cs-title {}.cs-text {}.cs-box {}

但有一类基于CSS属性构建的单命名反而更安全,它们比颜色这些类名还要安全,即使项目会引入外部CSS:.db { display: block; }.tc { text-align: center; }.ml20 { margin-left: 20px; }.vt { vertical-align: top; }

这种方式的命名更安全的原因在哪里呢?(1)这些选择器命名是面向CSS属性的,它们是超越具体项目的存在,只会被重复定义,但不会发生样式冲突。(2)面向CSS属性的命名是机械的、反直觉的,而面向语义的命名符合人类直觉,也就是说,对于一个标题,将它命名为title的人很多,但抛弃语义,直接使用tc命名的人却寥寥无几。更直白一点,从网上随机找两个CSS文件,其中title命名冲突的概率要比tc大好几个数量级。

这确实有些奇怪,如此短的命名反而不会产生冲突,这是我这10年来写过无数CSS所得出的结论。当然,我们最好还是尽可能降低冲突出现的概率,这样心里也踏实:.g-db { display: block; }.g-tc { text-align: center; }.g-ml20 { margin-left: 20px; }.g-vt { vertical-align: top; }

或者连前缀也直接省掉:.-db { display: block; }.-tc { text-align: center; }.-ml20 { margin-left: 20px; }.-vt { vertical-align: top; }

这样,一眼就能辨识这个类名是基于CSS属性创建的。

总结一下,除了多人合作、长期维护、不会引入第三方CSS的项目的全站公用样式可以使用单命名,其他场景都需要组合命名。

然而,即使将命名做到极致,也无法完全避免冲突,因为CSS reset的冲突是防不胜防的。例如,对于body标签选择器的设置,每个网站都不一样,很多第三方CSS甚至喜欢使用通配符:*, *::before, *::after { box-sizing: border-box; }

后面2个伪元素前面的星号是多余的,这不重要,重要的是这段CSS会给其他网站布局带来毁灭性的影响,导致大量错位和尺寸变化,因为所有元素默认的盒模型都被改变了。希望大家在实际开发中不会遇到这样不靠谱的第三方,也不要成为这么不靠谱的第三方。3.3.3 面向属性的命名和面向语义的命名

面向属性的命名指选择器的命名是跟着具体的CSS样式走的,与项目、页面、模块统统没有关系。例如,比较经典的清除浮动类名.clearfix:.clearfix:after { content: ''; display: table; clear: both; }

以及其他很多命名:.dn { display: none; } .db { display: block; } .df { display: flex; } .dg { display: grid; }.fl { float: left; }.fr { float: right; }.tl { text-align: left; }.tr { text-align: right; }.tc { text-align: center; }.tj { text-align: justify; }...

面向语义的命名则是根据应用元素所处的上下文来命名的。例如:.header { background-color: #333; color: #fff; }.logo { font-size: 0; color: transparent; }...

试读结束[说明:试读内容隐藏了图片]

下载完整电子书


相关推荐

最新文章


© 2020 txtepub下载