高效css选择符

关于前端性能一说,绝大多数的人都知道JS优化,DOM优化,但是你有没有考虑过CSS选择符优化?殊不知这个用来美化前端页面的东西也是一个性能的关键。而且往往我们都是背道而驰,借助前人铺垫好的道路我们来补习一下。

首 先,对于CSS的性能有一些最佳的实践,1.把样式表放在HEAD标签中以提升页面的逐步渲染速度;2.不要再IE中使用CSS表达式,因为它可能会被执 行成千上万次,从而导致打开页面的速度变慢;3.避免过多(如果可以完全避免的话最好)的行内样式,即style,因为这会增加下载页面内容的大小。另外 一个,也是最重要的话题就是CSS选择符的开销。CSS选择符由一系列初始化的参数组成,这些参数指明了要应用这个CSS规则的页面元素。

CSS选择符对性能的影响源于浏览器匹配选择符和文档元素时所消耗的时间,我们可以通过编写更高效的选择符来控制匹配耗时。要实现高效的选择符首先要理解选择符是如何进行匹配的。

如下列举出一些很常用的CSS选择符,我按照从最简单(最小开销)到最复杂(最大开销)的顺序列出:
#toc{margin-left:20px} //ID选择符,简单且高效,它用指定的ID匹配页面中唯一的元素。
.chapter{font-weight:bold} //类选择符,匹配所有类属性包含该名字的元素
a{text-decoration:none} //类型选择符,应用于指定元素类型的所有元素
h1 + #toc{margin-top:40px} //相邻兄弟元素选择符,即h1元素的同级且ID为toc的元素(该属性IE6不支持)
#toc > li{font-weight:bold} //子元素选择符,匹配父元素ID为toc的所有li元素(该属性IE6不支持)
#toc a{color:#444} //后代选择符,当第2个选择符是第1个选择符的后代(子,子孙等)时,后代选择符规则会进行匹配
*{font-family:Arial} //通配选择符,匹配文档中的每一个元素
[href=”#index”]{font-style:italic} //属性选择符,根据元素的属性是否存在或其属性值进行匹配,该规则匹配href属性值等于#index的元素,该选择符有4个变体。1.全等,使用=进 行匹配;2.判断属性是否存在,不考虑值使用[href];3.等于用空格分隔的属性值列表中的任意一个,使用[title~=”index”];4.等 于用连字符-分隔开的属性值列表中的任意一个,使用[LANG|=en]。(该属性IE6不支持)
a:hover{text-decoration:underline} //伪类和伪元素选择符,之前介绍的选择符类型都是基于DOM的,但某些预期的样式不能再DOM中表现,伪类和伪元素就是来解决这个问题的。其他的伪类还 包括:fitst-child(该属性IE6不支持)、:link、:visited、:active、:focus(该属性IE6/7不支 持)、:lang(该属性IE6/7不支持)。伪元素包括:first-line(该属性IE6不支持)、:first-letter(该属性IE6不支 持)、:before(该属性IE6/7不支持)、:after(该属性IE6/7不支持)

看看如下的规则#toc > li{font-weight:bold}我们中的大多数人,尤其是那些习惯从左向右阅读的人,可能猜想浏览器也是执行从左到右的匹配,因此推测该规则是这样匹配的:先找到页面中唯一的一个ID为toc的元素,然后找到他下边所有的li元素,然后进行CSS渲染。可是,你错了!

CSS选择符是从右到左匹配的

没错。就是这样,从右到左,知道这个以后,我们反过来再看这个选择符,其实他的开销相当高了,浏览器必须遍历所有的li元素并确定其父元素的ID是toc。其他的比如#toc a{color:#444}这样的选择符开销则更大,浏览器不但要查找所有的A标签,还要遍历DOM树去查找ID为toc的祖先元素,如果被评估的连接不上toc的后代,那么浏览器就要向上一级继续遍历直到文档的根节点。

规则都知道了,我们就可以从另外一个角度看CSS选择符,并将其调整得更高效,前辈给我们留下了宝贵的几点建议:

一:避免使用通配规则,除了传统意义上的通配选择符之外,我们的前辈Hyatt也把相邻兄弟选择符、子选择符、后代选择符和属性选择符都归纳到“通配规则”分类下,他推荐仅适用ID、类和标签选择符。

二:不要限定ID选择符:在页面中一个指定的ID只能对应一个元素,所有没必要额外添加限定符,例如DIV#toc是没有必要的,应简化为#toc。

三:不要限定类选择符:不要用具体的标签限定类选择符,而是根据实际情况对类名进行扩展。例如把li.chapter改为.li-chapter,或是.list-chapter更好。

四:让规则越具体越好,不要试图编写像ol li a这样的长选择符,最好是创建一个像.list-link一样的类。

五:避免使用后代选择符,通常处理后代选择符的开销是最高的。遵循下条规则。

六:避免使用标签-子选择符,如果有像#toc > li > a这样的基于标签的子选择符,那么应该使用一个类来关联每个标签元素,如.toc-link。

七:质疑子选择符的所有用途,再次提醒大家检查所有使用子选择符的地方,然后尽可能用具体的类取代它们。

八(我觉得这条特别实际特别靠谱特别实用):依靠继承,了解哪些属性可以通过继承而来,然后避免对这些属性重复指定规则。

九:这条是我根据第八条自己加的,说到重复,建议大家使用面向对象的CSS(OOCSS),尽量更多的使用可重复的样式,各位自己谷歌一下,会受益匪浅的。

了解了这些规则之后,根据实际需要权衡一下,然后开始从新书写更高效的CSS吧!


关注我

我的微信公众号:前端开发博客,在后台回复以下关键字可以获取资源。

  • 回复「小抄」,领取Vue、JavaScript 和 WebComponent 小抄 PDF
  • 回复「Vue脑图」获取 Vue 相关脑图
  • 回复「思维图」获取 JavaScript 相关思维图
  • 回复「简历」获取简历制作建议
  • 回复「简历模板」获取精选的简历模板
  • 回复「加群」进入500人前端精英群
  • 回复「电子书」下载我整理的大量前端资源,含面试、Vue实战项目、CSS和JavaScript电子书等。
  • 回复「知识点」下载高清JavaScript知识点图谱

每日分享有用的前端开发知识,加我微信:caibaojian89 交流