性能优化之CSS部分

在上一篇chrome调试里面讲到了渲染对页面的性能是非常关键的,其中就包括CSS。

从最原始的CSS代码到CSS3,后来的LESS、Sass、Stylus到现在的PostCSS,这门语言已经远远不是那么简单的。但也许有人会说,只要写出的CSS达到UI设计图一模一样的样式不就行了么,答案是肯定的,没有人会去关心产品是怎么实现的,除了你自己。

这里就不再教大家怎么去写CSS了,而是一起讨论一下专业CSS都有哪几点。

属性的使用

CSS常用属性不是特别多,所以上手也非常快。随着CSS3新增的一些动画属性,可能在低版本浏览器不识别,但现在都什么年代了,不需要担心太多。
有个网站CSSTrigger已经非常详细的介绍了每一个属性会不会触发layout事件,还有一些相应的注意事项。之前听说过有些公司的前端样式书写需要遵循先定位然后是字体颜色之类的,但现实是没有几个人会真的按照这上面去做,原因很简单,每个工程师都会有自己的习惯,再说现在CSS的伪类已经非常强大。

如何对属性来进行优化呢,答案是多种多样的。这里举一个优化绘制的例子,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/* The bad way */
.normal_way {
box-shadow: 0 1px 2px rgba(0,0,0,0.15);
transition: box-shadow 0.3s ease-in-out:
}

/* 鼠标悬停实现更大阴影的过渡 */
.normal_way:hover {
box-shadow: 0 5px 15px rgba(0,0,0,0.3);
}

/* The alternate way */
.better_way {
box-shadow: 0 1px 2px rgba(0,0,0,0.15);
}

/* 设置更大的阴影并将之隐藏 */
.better_way::after {
box-shadow: 0 5px 15px rgba(0,0,0,0.3);
opacity: 0;
transition: opacity 0.3s ease-in-out:
}

/* 鼠标悬停时实现更大阴影的过渡显示 */
.make-it-fast:hover::after {
opacity: 1;
}

实现最小的重新绘制,应该创建一个伪元素并对其opacity元素进行动画处理,使其以每秒60帧的动画模仿运动物体相同的效果。

1
2
3
4
5
6
7
8
9
10
11
// 不建议, 造成页面布局两次.
var newWidth = aDiv.offsetWidth + 10; // 读
aDiv.style.width = newWidth + 'px'; // 写
var newHeight = aDiv.offsetHeight + 10; // 读
aDiv.style.height = newHeight + 'px'; // 写

// 建议, 只有一次页面布局.
var newWidth = aDiv.offsetWidth + 10; // 读
var newHeight = aDiv.offsetHeight + 10; // 读
aDiv.style.width = newWidth + 'px'; // 写
aDiv.style.height = newHeight + 'px'; // 写

选择器的选取

如果CSS的id、class名还是用拼音或者阿拉伯数字的盆友,请你先去学习英语基本3000词汇。

具体可以参考我的CSS3 blog。

工具的使用

工欲善其事,必先利其器。选对了适合自己开发的工具,这样做起事来才能事半功倍。而且通过工具写出来的CSS代码可读性就不用说了,而且直接压缩后体积又小。这样无形中对CSS的优化又帮了一把手。

下面是3中CSS的写法,通过gulp来实现。其中需要的前提条件是你对node.js和gulp有一点的了解

PostCSS

它将是未来取代传统CSS代码的的利器,很多的牛人写出了很牛逼的插件,比如说lost,rucksack,使用它们比bootstrap强多了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 测试新一代的CSS写法
gulp.task('styles', function(){
var processors = [
lost,
rucksack,
prefixer_darcy({ browsers: ['last 2 versions'] }),
csswring,
];

return gulp.src('./assets/scss/darcy.css')
.pipe(postcss(processors))
.pipe(gulp.dest('./assets/css'))
.pipe(reload({stream: true}));
});

PostCSS + Sass

1
2
3
4
5
6
7
8
9
10
11
12
13
// 测试新一代未来的CSS写法
gulp.task('presass', function(){
var processors = [
precss({}),
autoprefixer({ browsers: ['last 2 versions'] }),
cssnext({compress: true})
];

return gulp.src('./assets/scss/presass.css')
.pipe(postcss(processors))
.pipe(gulp.dest('./assets/css'))
.pipe(notify({ message: 'presass task ok' }));
});

Sass

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// sass settings 
gulp.task('sass', function(){

var AUTOPREFIXER_BROWSERS = [
'ie >= 8',
'ie_mob >= 10',
'ff >= 30',
'chrome >= 34',
'safari >= 7',
'opera >= 23',
'ios >= 7',
'android >= 4.2',
'bb >= 10'
];

return gulp.src('assets/scss/linked.scss')
.pipe(sourcemaps.init())
.pipe(sass({outputStyle: 'compressed'})
.on('error', errorlog))
.pipe(autoprefixer(AUTOPREFIXER_BROWSERS))
.pipe(sourcemaps.write('../maps'))
.pipe(gulp.dest('./assets/css'))
.pipe(reload({stream:true}));
});

还有需要大家注意的是配置里面会有很多的坑,因为你要明白gulp-autoprefixer跟autoprefixer不是一回事,还有是每次npm install的时候都会遇到gulp-sass中的node-sass中一个文件搞不下来,这个时候就需要你科学上网了。

一本书叫做High Performance Browser Networking,大家有时间可以去看一看,免费的

浏览器优化的一些demo地址
https://github.com/udacity/web-workers-demo
http://udacity.github.io/news-aggregator/
http://andydavies.me/blog/2013/10/22/how-the-browser-pre-loader-makes-pages-load-faster/
http://udacity.github.io/60fps/lesson6/willChange/index.html
https://gist.github.com/paulirish/1579671
http://www.html5rocks.com/static/demos/parallax/demo-1a/demo.html
https://github.com/udacity/news-aggregator/tree/gh-pages/hints
https://github.com/udacity/news-aggregator
https://github.com/udacity/news-aggregator/blob/gh-pages/hints/all-bugs.md
https://github.com/udacity/news-aggregator/tree/solution
https://dl.dropboxusercontent.com/u/2272348/codez/udacity/box-recalc-style-slow.html
https://github.com/udacity/frontend-nanodegree-mobile-portfolio

https://github.com/google/ios-webkit-debug-proxy

API的使用https://github.com/HackerNews/API