今天写了一个CSS的小工具,也算是最近关于CSS和Web性能优化思考的一次实践。下面开始介绍一下,这个小工具主要功能有以下这些:
代码压缩
这个小工具其实是一个Default.aspx页面文件,我们只要把它放到网站CSS文件夹里面,保证这个页面命名是默认首页,然后把我们原来引用的CSS文件夹后面加一个问号就行了。用我的博客举个例子,我本来文章页面中有三个CSS引用:
然后我们只要改成这样就可以了:
这样之后有什么分别呢?加了问号之后,CSS引用都定向到我们的页面,页面根据后面的参数,读取CSS文件,然后把其中的无效空格,换行,注释全部清除掉。然后返回一个压缩后的CSS文件。可以点击下面两个链接看看压缩前后的效果:
压缩前:http://www.vinqon.com/codeblog/css/shCore.css
压缩后:http://www.vinqon.com/codeblog/css/?shCore.css
合并请求
对于一个Web优化*者来说,每一个Http请求都是那么的刺眼。这不得不说说一些让人纠结的事情。看过《高性能网站建设指南》的都知道,黄金法则第一条就是减少http请求,对于CSS来说,我们一般用这些方法来尽量减少请求:
1.合并CSS文件。一个页面往往引用了多个CSS文件,为了减少其请求数目,我们可以直接把该页面需要请求的CSS文件手动合并成为一个输出。但是,这带来的后果是,严重不利于代码的维护和管理。并且,合并之后的代码都是独立的,多个页面共用的代码无法缓存。
2.内联CSS代码。内联CSS的好处是完全杜绝了http请求,而且可以保证CSS里面附带的图片也能立刻请求,让页面更快完成渲染,QQ,新浪等的门户首页都使用了内嵌CSS。但是问题还是那个,首先不利于维护,其次是不能实现缓存。因为这些CSS每次都要下载,如果外联的话第二次请求的时候就可以直接使用缓存文件。
针对内联CSS代码的方案,之前我就想过做一个ASP.Net的插件,把在引用css的link标签改成服务器控件,输出页面的时候,控件会加载css文件内嵌到页面中,这样可以使内联代码也便于维护。
而针对合并CSS文件的方案,我在这个小工具中实现了请求时自动合并,这其实也不是什么新东西,好像之前也见过,还是用上面的例子,三个CSS文件合并:
只要用&把不同的文件名字链接起来,就会得到一个合并的输出。通过这样的实时合并,很好避免了手动合并带来的代码混乱,而且当有大量文件的时候,可以减少http请求数目,有明显的提升。
但是,不得不提一下的是:不一定全部CSS合并起来输出就是最好的,原因首先还是缓存问题,共用文件不应该合并,因为这样使得它每次都要重新下载。另外一个也是很重要的问题是,浏览器是会并行下载CSS文件的,如果分成多个文件,可以让最早下载下来的CSS文件立刻被使用,如果我们把全部乱七八糟的都合并起来,浏览器要等到整个CSS文档下载完毕才能使用,可能带来性能的倒退。所以,结论是:共用和基础的CSS文件不应该合并。
语法扩展
先说说目前比较经典的一种CSS代码组织结构,这也是《编写高质量代码—Web前端开发修炼之道》作者推荐的方案:
- 基础样式(主要包括对默认样式的Reset以及对用class选择器组合常用的样式)
- 全站样式(全站各个页面都要用到的样式,一般负责网站整体结构的构架)
- 页面样式(页面级的样式,针对页面细节的调整)
关于CSS代码组织不是本次主题,我想说一下的是上面粗体字提到的一种比较流行的方法:
然后我们在页面中这么使用:
这些写法其实也没什么特别,但是我觉得很值得探讨,没兴趣的可以直接跳过这一段。我们一般在页面编码时,都是先写好HTML,再去写样式。在写样式的时候我们要为某个标签应用某个样式,就得用各种选择符找到目标元素,然后赋予样式。这时候,无论是类,还是标签,ID,它们的角色都是选择者,区别只是ID用来选一个,标签和类多用来选择多个而已。但是在上面例子中,类的情况就有些不同,在上面那种类的样式定义的时候,我们不会想到这一定会用在哪里,我们只想到这些样式使用可能比较频繁,先写出来,以便复用,最后才去HTML标签上加上多个不同的class,组合成一个新的独立样式。这和直接在style上面写规则的不同是,style只能使用的CSS基本属性,是粒度最小的CSS规则,用class可以通过基本属性的组合,形成一定粒度,然后我们可以通过在多个标签使用不同类的组合形成最终样式。这样做一方面可以保证代码复用,另一方面又可以便于维护。其实上,这种方法更多有标签选择样式的意味,而类这个双向选择特性是源于 类选择符与标签之间可以实现多对多的关系。
但是,这种写法有一个弊端,就是不利于结构和样式的分离。样式出现在元素里面,一旦修改,很容易触碰到html代码。为了解决这个问题,我在这个小工具里进行了语法扩展,我们可以在样式表中使用多个class。看例子吧:
我们编写css的时候可以直接向上面那样写,然后输出会变成这样:
.clear{clear:both;}
很久之前就想过,如果css有这功能多好哇,代码可以高度复用了。这次终于弱弱地实现了一下了。需要注意的是,编译过程代码写得不太好,最好严格遵循css格式,譬如,每个规则后面都必须有分号。另外,也不支持嵌套。
感谢Gray Zhang的推荐,原来目前已经有不少强大CSS语法扩展的工具,譬如Sass,Lesscss,两者功能相似,后者甚至支持在客户端编译。
缓存设置
上面很多次提到过缓存,但是因为我们使用了页面输出,常常不能被浏览器缓存,这需要我们自己手动设置,只要在参数后面加上expire=分钟数,就可以了,譬如:
http://localhost:56349/MyBlog/CodeBlog/css/?global.css&expire=50001
这个小工具很多正则,有人可能会觉得服务器也应该缓存一下吧,我没有做服务器的缓存是因为我觉得客户端缓存已经ok了,而且在本机调试的时候,每次页面输出都是在10毫秒之内,缓不缓存对用户没有很明显的感觉。服务器我就不管啦~
最后,提供源文件下载。