使用purifycss精简css的两种方法详解
2017-03-03 21:09
495 查看
本文和大家分享的主要是使用purifycss精简css的相关内容,一起来看看吧,希望对大家学习CSS有所帮助。
随着项目的不断迭代,我们的css会不断变大,但通常页面上需要用到的样式并没有那么多,很多样式是无用的,而如果靠人工去剔除,吃力又容易出错。
有痛点就应该去想办法解决。那么有没有办法通过自动化来把这些无用的样式剔除呢?答案是肯定的,不然就没有这篇文章了。目前我能找到的有以下两种方案:
方案一:遍历样式表,通过dom选择器判断每个样式是否在页面中存在
这种方案很精准,通过筛选有用的选择器来去掉那些没有用到的选择器。换句话来,只保留被用到的样式,去掉没用到的样式。
但这个方案明显存在缺陷,如果在js里面对dom的操作(例如对dom添加一个class样式等操作),这些如何判断?很显然,如果是js中引用到了css样式的话,这种方案是解决不了的。
方案二:找到那些一定不会被用到的选择器,去掉这些即可
那么怎么确定一个选择器一定不会被用到?从选择器的类型来看,至少包括下面几种:
·标签选择器
·class选择器
·ID选择器
·相邻选择器
·父子选择器
·属性选择器
·...
具体有哪些,可以参考下面的 链接
这么多类型的选择器,如果简单以字符解析js,想在js中确定用到了某个选择器,无疑是比较困难的事情。但我们换个角度来思考,不管选择器类型多复杂,它们都是由单词组成的,比如:
h1 => ["h"]
.a .d => ["a", "c"]
.ab-c => ["ab", "c"]
#text => ["text"]
.ab-c #text => ["ab", "c", "text"]
因此一个合法的选择器,我们可以看作是一组单词的集合。
接着,再想想我们在html或者js里面是如果引用这些选择器的?无非就是:
<div class="ab-c">
<span id="text"></span>
</div>
$("text").addClass(".a");
那么对于一个选择器来说,在html或者js被引用的话,那么html或者js代码里面一定会出现这个选择器的所有单词。如果没有出现或者没有全部出现的话,证明这个选择器是没有被用到的。
比如上面例子中:
选择器 h1 的单词集合 ["h"] 在html或者js中并没出现,因此选择器h1是无用的。
选择器 .a .d 的单词集合 ["a",
"d"] 在js中只出现了单词 a ,而没有出现单词 d ,因此选择器 .a
.d 也是无用的。
因此, 怎么确定一个选择器一定不会被用到 这个问题,就转化成, 如何确定一个选择器的单词集合是否是html或者js代码中的单词集合的子集
这个问题。
那么判断一个选择器的单词集合是否是html或者js代码中的单词集合的子集,如果是就保留,如果不是就丢弃掉好了。
这种方案通过剔除一定不会用到的选择器,换句话来说,它只能知道某个选择器可能被用到,无法确定某个选择器是一定会用的到。
如果有仔细注意上面的例子,就会发现如果我们的html结构是这样的,选择器 .ab-c 依旧会被保留下来
<div class="ab">
<span class="c">span>
也就是说这种方案也是还是有缺陷的,不能精准地确定某个选择器一定会用到,会存在漏剔除的情况(但绝不会出现误剔除的情况)。
在实际应用中,我们发现这种方案还是能剔除很多不必要的样式(所以目前测试的案例不多):
因此,从原理和效果上来看,第二种方案来实现剔除css是极不错的,在实际运用中,采用开源的 purifycss (毕竟有现成的,就没必要自己造轮子了)。
使用purifycss的一些细节和注意
·精简外部css的时候,需要注意内部是否以相对路径引用其他的资源(图片,字体等)
举个例子,我的html结构和css引用是这样的:
<link rel="stylesheet" href="//res.wx.qq.com/wechatgame/static/game/dist/css/style-notification.fb62b095.css">
<div class="bg">div>
而 style-notification.fb62b095.css 这个css是属于外部的一个css,它的代码里用到一张背景:
.bg {
background-image: url("../../images/bg.jpg");
}
那这时候我精简css的话,把这个css转化成我们自己的cdn( //wximg.gtimg.com/wxgame/webpack/ddz/mincss/style-notification_fb62b095.css ), 那么里面的代码自然也是:
.bg {
background-image: "../../images/bg.jpg";
}
而此时再访问我们的页面的时候,就会发现背景加载不出来了,控制台显示图片404了。原因很简单:
../../images/bg.jpg 这个相对路径对于 //res.wx.qq.com/wechatgame/static/game/dist/css/style-notification.fb62b095.css 来说,它的真实路径是//res.wx.qq.com/wechatgame/static/game/dist/images/bg.jpg , 而对于 //wximg.gtimg.com/wxgame/webpack/ddz/mincss/style-notification_fb62b095.css 来说,它的真实路径是 //wximg.gtimg.com/wxgame/webpack/ddz/mincss/images/bg.jpg 。而我们在上传cdn,并没有上传//wximg.gtimg.com/wxgame/webpack/ddz/mincss/images/bg.jpg ,所以就出现图片加载不出来的情况。
解决:在精简css的时候,需要把css里面的相对路径替换成绝对路径
// 将css中的引用的相对路径转化为绝对路径
function relative2absolute(cssContent,
base) {
return cssContent.replace(/url\([\"\']?([^\)]+)[\"\']?\)/g, function(input,
_url) {
if( isRemotePath(_url)) {
return input;
}
return "url(" + url.resolve(base, _url) + ")";
});
}
·精简css后,破坏了通用模块css的缓存
这其实是一个取舍问题。把很多通用css放在一个通用模块里面,页面加载的时候,可以利用浏览器缓存加快速度。而如果精简css的话,意味着每个页面所用到的通用模块都不一样,自然就用不了缓存。
解决:不精简通用模块css,只精简具体业务相关的css。我的实现是给link加个标志 min-css="true" :
<link rel="stylesheet" href="//res.wx.qq.com/wechatgame/static/game/wgui/css/wgui.min.css">
<link rel="stylesheet" href="//res.wx.qq.com/wechatgame/static/game/dist/css/style-notification.fb62b095.css"
min-css='true'>
这样子,只构建精简带有标志位的css,通用模块的css仍可以利用缓存,而具体业务相关的css可以尽可能剔除无用的样式,减少体积。
来源:SegmentFault
随着项目的不断迭代,我们的css会不断变大,但通常页面上需要用到的样式并没有那么多,很多样式是无用的,而如果靠人工去剔除,吃力又容易出错。
有痛点就应该去想办法解决。那么有没有办法通过自动化来把这些无用的样式剔除呢?答案是肯定的,不然就没有这篇文章了。目前我能找到的有以下两种方案:
方案一:遍历样式表,通过dom选择器判断每个样式是否在页面中存在
这种方案很精准,通过筛选有用的选择器来去掉那些没有用到的选择器。换句话来,只保留被用到的样式,去掉没用到的样式。
但这个方案明显存在缺陷,如果在js里面对dom的操作(例如对dom添加一个class样式等操作),这些如何判断?很显然,如果是js中引用到了css样式的话,这种方案是解决不了的。
方案二:找到那些一定不会被用到的选择器,去掉这些即可
那么怎么确定一个选择器一定不会被用到?从选择器的类型来看,至少包括下面几种:
·标签选择器
·class选择器
·ID选择器
·相邻选择器
·父子选择器
·属性选择器
·...
具体有哪些,可以参考下面的 链接
这么多类型的选择器,如果简单以字符解析js,想在js中确定用到了某个选择器,无疑是比较困难的事情。但我们换个角度来思考,不管选择器类型多复杂,它们都是由单词组成的,比如:
h1 => ["h"]
.a .d => ["a", "c"]
.ab-c => ["ab", "c"]
#text => ["text"]
.ab-c #text => ["ab", "c", "text"]
因此一个合法的选择器,我们可以看作是一组单词的集合。
接着,再想想我们在html或者js里面是如果引用这些选择器的?无非就是:
<div class="ab-c">
<span id="text"></span>
</div>
$("text").addClass(".a");
那么对于一个选择器来说,在html或者js被引用的话,那么html或者js代码里面一定会出现这个选择器的所有单词。如果没有出现或者没有全部出现的话,证明这个选择器是没有被用到的。
比如上面例子中:
选择器 h1 的单词集合 ["h"] 在html或者js中并没出现,因此选择器h1是无用的。
选择器 .a .d 的单词集合 ["a",
"d"] 在js中只出现了单词 a ,而没有出现单词 d ,因此选择器 .a
.d 也是无用的。
因此, 怎么确定一个选择器一定不会被用到 这个问题,就转化成, 如何确定一个选择器的单词集合是否是html或者js代码中的单词集合的子集
这个问题。
那么判断一个选择器的单词集合是否是html或者js代码中的单词集合的子集,如果是就保留,如果不是就丢弃掉好了。
这种方案通过剔除一定不会用到的选择器,换句话来说,它只能知道某个选择器可能被用到,无法确定某个选择器是一定会用的到。
如果有仔细注意上面的例子,就会发现如果我们的html结构是这样的,选择器 .ab-c 依旧会被保留下来
<div class="ab">
<span class="c">span>
也就是说这种方案也是还是有缺陷的,不能精准地确定某个选择器一定会用到,会存在漏剔除的情况(但绝不会出现误剔除的情况)。
在实际应用中,我们发现这种方案还是能剔除很多不必要的样式(所以目前测试的案例不多):
因此,从原理和效果上来看,第二种方案来实现剔除css是极不错的,在实际运用中,采用开源的 purifycss (毕竟有现成的,就没必要自己造轮子了)。
使用purifycss的一些细节和注意
·精简外部css的时候,需要注意内部是否以相对路径引用其他的资源(图片,字体等)
举个例子,我的html结构和css引用是这样的:
<link rel="stylesheet" href="//res.wx.qq.com/wechatgame/static/game/dist/css/style-notification.fb62b095.css">
<div class="bg">div>
而 style-notification.fb62b095.css 这个css是属于外部的一个css,它的代码里用到一张背景:
.bg {
background-image: url("../../images/bg.jpg");
}
那这时候我精简css的话,把这个css转化成我们自己的cdn( //wximg.gtimg.com/wxgame/webpack/ddz/mincss/style-notification_fb62b095.css ), 那么里面的代码自然也是:
.bg {
background-image: "../../images/bg.jpg";
}
而此时再访问我们的页面的时候,就会发现背景加载不出来了,控制台显示图片404了。原因很简单:
../../images/bg.jpg 这个相对路径对于 //res.wx.qq.com/wechatgame/static/game/dist/css/style-notification.fb62b095.css 来说,它的真实路径是//res.wx.qq.com/wechatgame/static/game/dist/images/bg.jpg , 而对于 //wximg.gtimg.com/wxgame/webpack/ddz/mincss/style-notification_fb62b095.css 来说,它的真实路径是 //wximg.gtimg.com/wxgame/webpack/ddz/mincss/images/bg.jpg 。而我们在上传cdn,并没有上传//wximg.gtimg.com/wxgame/webpack/ddz/mincss/images/bg.jpg ,所以就出现图片加载不出来的情况。
解决:在精简css的时候,需要把css里面的相对路径替换成绝对路径
// 将css中的引用的相对路径转化为绝对路径
function relative2absolute(cssContent,
base) {
return cssContent.replace(/url\([\"\']?([^\)]+)[\"\']?\)/g, function(input,
_url) {
if( isRemotePath(_url)) {
return input;
}
return "url(" + url.resolve(base, _url) + ")";
});
}
·精简css后,破坏了通用模块css的缓存
这其实是一个取舍问题。把很多通用css放在一个通用模块里面,页面加载的时候,可以利用浏览器缓存加快速度。而如果精简css的话,意味着每个页面所用到的通用模块都不一样,自然就用不了缓存。
解决:不精简通用模块css,只精简具体业务相关的css。我的实现是给link加个标志 min-css="true" :
<link rel="stylesheet" href="//res.wx.qq.com/wechatgame/static/game/wgui/css/wgui.min.css">
<link rel="stylesheet" href="//res.wx.qq.com/wechatgame/static/game/dist/css/style-notification.fb62b095.css"
min-css='true'>
这样子,只构建精简带有标志位的css,通用模块的css仍可以利用缓存,而具体业务相关的css可以尽可能剔除无用的样式,减少体积。
来源:SegmentFault
相关文章推荐
- 详解使用python的logging模块在stdout输出的两种方法
- 刷新View视图的两种方法—invalidate()和postInvalidate()的区别和使用详解
- css类选择器的使用方法详解
- iOS同一项目多个Target的快速实现方法 - 两种使用场景详解
- iOS同一项目多个Target的快速实现方法 - 两种使用场景详解
- CSS: list-style 和 inline使用方法详解
- 使用Java构造和解析Json数据的两种方法(详解二)
- 详解webpack打包时排除其中一个css、js文件或单独打包一个css、js文件(两种方法)
- jQuery autoComplete插件两种使用方式及动态改变参数值的方法详解
- Java构造和解析Json数据的两种方法详解一:使用org.json库
- jQuery addClass(), removeClass(),toggleClass(),css()方法使用详解
- 前端html、CSS快速编写代码插件-Emmet使用方法技巧详解
- jQuery autoComplete插件两种使用方式及动态改变参数值的方法详解
- Eclipse中perspective(透视图)的两种使用方法详解
- css类选择器的使用方法详解
- Java构造和解析Json数据的两种方法详解二:使用JSON-lib库
- 使用Java构造和解析Json数据的两种方法(详解一)
- css类选择器的使用方法详解
- CSS导入使用及引用的两种方法
- Java语言中flush()函数作用及使用方法详解