CSS选择器基础

篇首语

也许你觉得你已经理解了CSS方面的知识了,确实CSS和HTML的学习特点也是先易后难。如果你觉得CSS很简单的话,你可以直接通过点击目录跳转到CSS优先级部分看一下,如果你觉得这些也都是小case。 那么你可以跳过本文,当然你也可以当成一篇笑话来看。不过本文的知识都是我的经验和总结,如果能找到我文章中的错误,再下更是感激不尽,我又有可以修正自己错误的机会了。

啰嗦的开头

愉快的写着代码,啪啦啪啦的敲击着键盘。音响飘出若有若无的钢琴曲,空气中弥漫着刚刚磨好的咖啡香味。心中赞叹着生活真特么美好啊。突然看到新来的同事走进我的办公室,我心中立马感叹,要不是来中断我的工作的话就特么更美好了。果不其然是来问问题的,哎~这小子上学的时候不好好学习,毕业开始工作了这才感受到职场上技术人员之间那种竞争压力了,才来好好学习,何必当初啊。不过知道学的人总是会不断进步的。

腆着个脸在心中数落着别人,回想自己何尝不是上学的时候拼命玩,上班了还是拼命玩,结婚了才感到压力,才去自觉地学习。哎~说多了都是泪!不过这小家伙的学习态度还是值得肯定的,虽然问的问题都比较基础,但是从整体来看,问的问题也是在逐步提高着难度。其实我写博客也是为了应付这些问问题的小家伙们,先让他们自己看,如果不理解再来问我。这样不会太耽误我工作的进度。先看看这小子来问什么问题吧。

果不其然,是个比较基础的问题。是关于兄弟选择器的。好吧,前面的废话终于铺垫完成。开始写博客正文吧——本篇可以叫做CSS基础之旅了。感谢这些小家伙们让我的基础也夯实了许多,有些比较基础的东西因为用的不是很多,过段时间很容易遗忘。当“老师”去讲解的时候,也让自己更好的去记忆和理解。

CSS基础

想要了解掌握CSS选择的相关知识,就必须先要了解CSS的一些基础知识。

CSS解决了一个普遍的问题

HTML标签原本被设计为用于定义文档内容。通过使用 <h1><p><table> 这样的标签,HTML的初衷是表达“这是标题”、“这是段落”、“这是表格”之类的信息。同时文档布局由浏览器来完成,而不使用任何的格式化标签。

由于两种主要的浏览器(Netscape 和Internet Explorer)不断地将新的HTML标签和属性(比如字体标签和颜色属性)添加到HTML规范中,创建文档内容清晰地独立于文档表现层的站点变得越来越困难。

为了解决这个问题,万维网联盟(W3C),这个非营利的标准化联盟,肩负起了HTML标准化的使命,并在 HTML4.0之外创造出样式(Style)。

所有的主流浏览器均支持层叠样式表。

以上说明了CSS的由来,自从这货诞生伊始就注定了它的不平凡。不管是理论模型还是项目实践毫无争议的证明了CSS在WEB设计领域的突破性作用。从前端工程师的视角来看待CSS,不亚于看到活生生的超人那样震撼,层叠样式表CSS以救世主的姿态将当时的工程师从苦逼的工作中解放了出来——样式和结构的分离,让维护和开发的工作变的更具效率;也让WEB代码更具备可读性。

CSS样式表的构成比较简单,样式表由多条样式或者叫规则的东西组合而成。我个人比较习惯的叫规则,具体叫什么无所谓,如果愿意的话我们可以叫它们阿狗阿猫什么的,关键点在于理解。每一条CSS规则主要由两个部分构成:选择器,以及一条或多条声明;每条声明由一个属性和一个组成。

CSS规则由选择器和声明构成,声明由属性和值构成。

很简单不是么?网页最后呈现出来的效果,就是由一个个的CSS规则组成的;而每个规则是由选择器和声明构成;声明则是由属性和值组成。在合理使用选择器的情况下,能熟练运用每一个CSS属性并了解其值的含义的人,才是高手中的高手。从某种方面来讲,我们平常CSS知识的积累过程,其实就是CSS属性及其值的知识和运用的积累过程。

CSS工作原理

在用户访问一个网页的时候,页面会加载到浏览器当中。表面上看页面唰~的一下就出来了,但是其背后较深层的工作可不是唰一下这么简单。访问的本质其实是下载web服务器上的资源,然后通过浏览器的渲染功能,渲染出设计者的设计意图。这样从总整体上来,浏览器的工作原理是下面的顺序:

  1. 浏览器从服务器上下载资源的顺序是从上到下,浏览器的渲染的顺序也是从上到下,下载和渲染是同时进行的。
  2. 在渲染到页面的某一部分时,当前部分之前的所有部分都已经下载完成(并不是所有相关联的元素都已经下载完)。
  3. 如果遇到语义解释性的标签嵌入文件(JS脚本,CSS样式),那么此时浏览器的下载过程会启用单独连接进行下载。
  4. 下载后进行文件的解析。解析过程中,同时停止其位置以下所有元素的下载。
  5. 样式表在下载完成后,将和以前下载的所有样式表一起进行解析,解析完成后,将对此前所有元素(含以前已经渲染的)重新进行渲染。
  6. JS、CSS中如有重定义,后定义函数将覆盖前定义函数。

第五条也就决定了CSS渲染过程中,后面的规则将会覆盖前面的规则,例如下图:

后面的规则将会覆盖前面的规则

而且在2-5条中也点明了CSS渲染效率的关键点:

  1. css选择器的查询定位效率
  2. 浏览器的渲染模式和算法
  3. 要进行渲染内容的大小

我们很多关于CSS的优化方案其实都是从这三个发面来着手的,具体的优化原则将在本文的最后简单介绍。下面我们来看看CSS渲染工作原理;

在单独的CSS文件中渲染顺序是从上到下,依次渲染。对于同一元素的的相同渲染属性的值有差异的,后面的覆盖前面的。单个CSS规则中的选择器匹配顺序不是习惯上的从左到右进行查找,而是从右到左进行查找。比如说CSS规则div#divBox.red{color:red;},浏览器的查找顺序如下:先查找html中所有class=‘red’的元素,找到后,再判断该元素的父元素中是否有id为divBox的div元素,如果都存在则CSS匹配上。浏览器从右到左进行查找的好处是为了尽早过滤掉一些无关的样式规则和元素。关于CSS的工作原理其实只有这么多,下面要看本文的重点——CSS选择器。

CSS选择器基础

CSS属性比较多,靠专门的学习在短时间内不可能全部掌握,只能依靠日常的积累。但是CSS选择器的知识就相对简单和集中一点。这一大段的内容就是本文的重点——CSS选择器。

CSS选择器最主要的基础选择器。

选择器 含义
* 通用元素选择器,匹配页面任何元素。(这也就决定了我们很少使用)
#id id选择器,匹配特定id的元素
.class 类选择器,匹配class包含(不是等于)特定类的元素
element 标签选择器。例如:li、div等标签

下面我们拿出几个CSS规则来举例子,CSS规则div{color:red;}中的div就是标签选择器,它的存在等于是改变了标签div的默认样式。CSS规则.nav{color:red;}中的.nav是类选择器,其特征就是前面有一个**.**。CSS规则#sidebar{color:red;}中的#sidebar是类选择器,其特征就是前面有一个**#**,这也是和类选择器的区别。

除了基础选择器之外常用的还有伪类选择器和伪元素选择器,关于伪类和伪元素的区别可以看老衲以前的文章《伪类与伪元素,傻傻分不清楚》。例如常用的:hover{color:blue;}就是一个伪类选择器,它的作用就是当鼠标经过时元素的样式。当然了伪类选择器不是单单的只有这一个。

这些基础选择器只是我们建设庞大“前端建筑”的一些砖头水泥,要把这些“材料”组合起来就需要组合选择器大展神威了。

选择器 含义
E,F 多元素选择器,用”,分隔,同时匹配元素E或元素F
E F 后代选择器,用空格分隔,匹配E元素所有的后代(不只是子元素、子元素向下递归)元素F
E>F 子元素选择器,用”>”分隔,匹配E元素的所有直接子元素
E+F 直接相邻选择器,匹配E元素之后的相邻的同级元素F
E~F 普通相邻选择器(弟弟选择器),匹配E元素之后的同级元素F(无论直接相邻与否)
.class1.class2 这个姑且也算一个吧,没什么名字,匹配类名中既包含class1又包含class2的元素

因为组合选择器比较好理解所以不再举例了,这里面要提的是组合选择器并不是只能写两层,第一段中的小朋友就是有这种误解,认为只能写E>F这样的,其实我们写可以写E>F.class Element这样。不过在使用组合选择器的时候,一定要注意优先级的问题,关于优先级在本文后面也会被提及。

除了上面介绍的三种选择器之外还高级的属性选择器,关于属性选择器的用法参见下表。

选择器 含义
E[attr] 匹配所有具有属性attr的元素,div[id]就能取到所有有id属性的div
E[attr=value] 匹配属性attr值为value的元素,div[id=test],匹配id=test的div
E[attr~=value] 匹配所有属性attr具有多个空格分隔、其中一个值等于value的元素
E[attr|=value] 匹配所有att属性具有多个”-”分隔、其中一个值以value开头的元素,主要用于lang属性,比如“en”、“en-us”
E[attr^=value] 匹配属性attr的值以value开头的元素
E[attr$=value] 匹配属性attr的值以value结尾的元素
E[attr*=value] 匹配属性attr的值包含value的元素
CSS属性选择器实例

具体的用法不在本文中举例了,我有一个仿别人的综合性demo,我觉得它很全面的介绍了关于CSS选择器的用法和效果。具体地址是《CSS选择器演示》

CSS选择器优先级*

CSS如何去渲染,谁先渲染,谁后渲染。谁的渲染有效,谁的渲染无效。这个被称为CSS选择器的优先级。CSS选择器的优先级看起来很简单,其实并没有那么简单。我们都知道CSS样式有四种存放方式:

  1. 外部样式:通过link标签引入CSS样式;
  2. 内页样式:写在HTML页面里面的style标签里面;
  3. 行内样式:写在对应标签的style属性里面。
  4. @import url引入样式:CSS代码的代码片段中引入另外的样式文件。

最后一种@import url一般不推荐使用,前三种方式的优先级是:行内样式>内页样式>外部样式。不过这样比较优先级的意义不大,因为目前所有的样式都是使用外部样式。而在同一个CSS文件中的权重优先级可以参加下表:

  • 不同级别中的优先级顺序
  1. 在属性后面使用 !important会覆盖页面内任何位置定义的元素样式。
  2. 作为style属性写在元素内的行内样式
  3. id选择器
  4. 类选择器
  5. 标签|伪类|属性选择器
  6. 伪元素选择器
  7. 选择器继承
  8. 通配符选择器
  9. 浏览器自定义
  • 同一级别的优先级顺序
  1. 同一级别中后写的会覆盖先写的样式

其实造成这样的优先级的原因是因为我们给他们赋予了不同的权重值:

  • important的权重为1,0,0,0(1000)
  • ID的权重为0,1,0,0(100)
  • 类的权重为0,0,1,0(10)
  • 标签的权重为0,0,0,1(1)
  • 伪类的权重为0,0,1,0(10)
  • 属性的权重为0,0,1,0(10)
  • 伪对象的权重为0,0,0,1(1)
  • 通配符的权重为0,0,0,0
  • 继承的权重比较特殊为0.1

有了这些权重值的存在,才能让我们的组合选择器有了不通的呈现效果;

/*CSS选择器权重*/
p{color:red;}  /*标签,权值为1*/

p span{color:green;}  /*两个标签,权值为1+1=2*/

p>span{color:purple;}/*权值与上面的相同,因此采取就近原则*/

.warning{color:white;}  /*类选择符,权值为10*/

p span.warning{color:purple;}  /*权值为1+1+10=12*/

#footer .note p{color:yellow;}  /*权值为100+10+1=111*/

这些就是优先级的计算方法,具体CSS优先级怎么会影响到渲染结果,我估计你也是一脸懵逼,看一张图,就能明白优先级对渲染结果的影响了。图中已经有示例的所有源码了,建议自己再试验体会一下。

CSS优先级对渲染结果

CSS优先级高的获得了渲染权限所以em标签内的颜色是权重比较高的CSS规则的结果——即蓝色。

关于优先级有一种很有趣的情况,就是用JS来对DOM文件进行操作而产生CSS样式,会因浏览器的差异而呈现不同的渲染结果。这个我也只是看到过相关的文章并没有具体的试验来验证。有机会的话我应该会写一篇文章来专门讨论这个问题。

不知不觉已经写了很多,但是关于CSS的知识还有一点没有介绍完。而且我也觉得上面介绍的不是很详细。再多说一次,关于具体选择器的用法和渲染效果多看下我的DEMO《CSS选择器演示》可能会有不错的收获。

个人觉得目前为止写下的文字已经远远的超出了本文题目的范围,因为这些不再是基础的范畴——已经几乎是关于CSS选择器方面的所有知识了。觉得有必要可以停笔了,想了下,还是把这篇臭长的文章给做一个完结吧。

书写规则及优化原则

CSS的书写顺序,会影响到渲染效率和我们阅读代码的效率。正确的书写顺序也能达到CSS优化的效果,看了一篇“歪果仁”写的关于CSS的书写顺序。我贴出来共同学习下。

  1. 位置属性(position, top, right, z-index, display, float等)
  2. 大小(width, height, padding, margin)
  3. 文字系列(font, line-height, letter-spacing, color- text-align等)
  4. 背景(background, border等)
  5. 其他(animation, transition等)

正确的CSS的书写规则也能精简代码并提高阅读体验。配合前人的经验和个人的经验,我列了个表:

  1. 使用CSS缩写属性。例如padding、background等。
  2. 去掉小数点前的“0”。例如0.3em可以简称成.3em。
  3. 简写命名(约定俗成的可以简写)。例如.nav。
  4. 16进制颜色代码缩写。例如#fff。
  5. 不要随意使用id选择器。
  6. 使用连字符“-”连接选择器长命名。
  7. 为选择器添加状态前缀。
  8. 合理利用CSS样式继承规则。
  9. 避免过于紧凑的约束条件。例如:.nav ul li可以写成.nav li

关于CSS优化我在前文已经说明了有几个着手点,例如CSS Sprite技术可以减少http请求达到优化的目的,在此不过多说明,在我们理解原理的前提下,多使用工具也是提高工作效率的手段之一。CSS Lint就是一款比较优秀的CSS优化检测工具。它除了能发现CSS书写问题外,还能提升CSS的性能。它的工作原理基于一定的规则和标准。关于规则有一篇很优秀的博客介绍过,但是我这边打不开这篇文章。万幸的是有人转载过,我也懒省事直接剪贴过来吧。

修复解析错误(Parsing errors should be fixed)
避免使用多类选择符(Don’t use adjoining classes)
IE6以及更古老的浏览器对类似.foo.bar的多类选择符解析不正确,参考IE6下的多类选择符一文。

移除空的css规则(Remove empty rules)
这个规则不包含任何属性,类似:.foo { }空规则的产生原因一般来说是为了预留样式。去除这些空规则无疑能减少css文档体积。

正确使用display的属性(Use correct properties for a display)
由于display的作用,某些样式组合会无效,徒增样式体积的同时也影响解析性能。CSS Lint会检查一下几点:
display:inline后不应该再使用width、height、margin、padding以及float。
display:inline-block后不应该再使用float。
display:block后不应该再使用vertical-align。
display:table-*后不应该再使用margin或者float。

不滥用浮动(Don’t use too many floats)
虽然浮动不可避免,但不可否认很多css bug是由于浮动而引起。CSS Lint一旦检测出样式文件中有超过10次的浮动便会提示警告。

不滥用web字体(Don’t use too many web fonts)
对于中文网站来说Web Fonts可能很陌生,国外却很流行。web fonts通常体积庞大,而且一些浏览器在下载web fonts时会阻塞页面渲染损伤性能。

不声明过多的font-size(Don’t use too may font-size declarations)
这是设计层面的问题,设计精良的页面不会有过多的font-size声明。

不在选择符中使用ID标识符(Don’t use IDs in selectors)
主要考虑到样式重用性以及与页面的耦合性。

不给h1~h6元素定义过多的样式(Don’t qualify headings)
全站统一定义一遍heading元素即可,若需额外定制样式,可使用其他选择符作为代替。

不重复定义h1~h6元素(Heading styles should only be defined once)

值为0时不需要任何单位(Zero values don’t need units)

标准化各种浏览器前缀(Vendor prefixed properties should also have the standard)
通常将浏览器前缀置于前面,将标准样式属性置于最后,类似:
.foo {-moz-border-radius: 5px;border-radius: 5px; }

使用CSS渐变等高级特性,需指定所有浏览器的前缀(CSS gradients require all browser prefixes)

避免让选择符看起来像正则表达式(Avoid selectors that look like regular expressions)
CSS3添加了一些类似~=等复杂属性,也不是所有浏览器都支持,需谨慎使用。

遵守盒模型规则(Beware of broken box models)

里面有些规则在前面的书写规则中也有提及,但是我觉得他的更为全面一些。

好吧,我觉得应该也差不多了,以后再来做修改吧。我要闪了……


全文完~
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,198评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,663评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,985评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,673评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,994评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,399评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,717评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,407评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,112评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,371评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,891评论 1 256
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,255评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,881评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,010评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,764评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,412评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,299评论 2 260

推荐阅读更多精彩内容

  • 问答题47 /72 常见浏览器兼容性问题与解决方案? 参考答案 (1)浏览器兼容问题一:不同浏览器的标签默认的外补...
    _Yfling阅读 13,625评论 1 92
  • 一.class 和 id 的使用场景? name:指定标签的名称应用场景:①form表单:name可作为传递给服务...
    Sunset125阅读 897评论 0 0
  • 前端必读:浏览器内部工作原理[https://kb.cnblogs.com/page/129756/] 作者: T...
    我是强强阅读 1,099评论 0 2
  • 简介浏览器可以被认为是使用最广泛的软件,本文将介绍浏览器的工 作原理,我们将看到,从你在地址栏输入google.c...
    听风阁阅读 3,200评论 0 7
  • 当我搬起砖头时,我无法拥抱你;当我放下砖头时,我无法养活你!虐不虐,你就说虐不虐~扯得有点多了,回归主题~ 先贴一...
    舟阳阅读 12,303评论 2 12