(注:本人现已不在石豆任职,且石豆官网又进行了一次新的改版,故本文章内容已不再匹配石豆现有官网)
这俩星期主要致力于公司官网的改版,今天也算是比较完整地上线(暂时还是全静态的),可以在 http://www.shidou.com 查看效果(旧版是http://www.shidou.com/sdcm/ )。
效果还不错,主要提升了交互以及首屏速率。就加载速度来说,从下图(上方为旧版,下方为新版)可以看出白屏时间和首屏时间均较大幅度下滑,鉴于requireJS无阻塞加载模块以及部分图片懒加载的处理,也很好地把首屏加载时间跟整页加载时间分开:
再次访问的速度也算是翻了几倍:
先说说一些遗憾的地方吧,毕竟不是大企业那样资源充足,所以没额外的服务器来做静态资源CDN处理,而且gulp给静态资源加md5后缀的方式跟requireJS实在难配合,故也暂不考虑给页面加expire头。
另外一些gzip、Etag之类的后端优化,也不属于我这边能管理的范畴了,所以有些想优化的东西还是蛮有心无力。
下面还是稍微唠嗑点有趣的东西。
兼容处理
新版项目要求是兼容到IE7,但页面上的确使用了很多的CSS3特性,对于不支持的浏览器只能做优雅降级的处理。
以产品介绍页的第一个动画来说,以常规形式使用了浏览器判断标签来显示不同内容(IE9-仅显示一张图片):
<!--[if lte IE 9 ]><div class="low"></div><![endif]--> <!--[if (gt IE 9)|!(IE) ]><!--> <div class="anm-wrap monitored"> <div class="bottom-wrap"> <span class="l1-1"></span> <span class="l1-2"></span> <span class="l2-1"></span> <span class="l2-2"></span> <span class="l3"></span> <span class="l4"></span> <span class="l5-1"></span> <span class="l5-2"></span> <span class="l6-1"></span> <span class="l6-2"></span> <div class="c1-1"></div> <div class="c1-2"></div> <div class="c2-1"></div> <div class="c2-2"></div> <div class="c3"></div> <div class="c4"></div> <div class="c5-1"></div> <div class="c5-2"></div> <div class="c6-1"></div> <div class="c6-2"></div> </div><div class="top"></div> </div><!--<![endif]--> </div>
而在其它css3动画模块上,则是尽量使用 translate3d 来取代 translateX/Y,原因是IE9不支持这个特性,那么可以在它忽略动画(transition/animation)的情况下也忽略为了动画而设置的方位偏移:
不过有些动画毕竟需要用上透明度opacity,如动画起始点设置opacity:0,会导致IE9在不支持动画的情况下也显示为透明度0,那么就得常规使用css hack做额外处理。
但在使用gulp-sass编译sass过程中,会发现它经常会把一些css hack的特定符号给忽略掉(见issue),故在一位朋友的建议下采用他们公司的hack方法——类区分处理。主要是在html标签加入对应浏览器的css类名:
<!--[if IE 7 ]> <html class="ie7" lang="zh-cn"><![endif]--> <!--[if IE 8 ]> <html class="ie8" lang="zh-cn"><![endif]--> <!--[if IE 9 ]> <html class="ie9" lang="zh-cn"><![endif]--> <!--[if (gt IE 9)|!(IE) ]><!--> <html lang="zh-cn"><!--<![endif]-->
后续咱自然可以很方便地在样式中hack任意IE浏览器,比如
.ie9 .pd-wrap3 .intro2{ .p-wrap>span,div.info{opacity: 1;} }
另外不得不说,在做CSS3动画处理过程中最恼人的无异于要写一堆兼容代码,如光是一个 transition 就会有 -webkit/moz/ms/o- 几种前缀。
于是乎果断拿sass封装一个样式库来提高工作效率,例如上述的 transition 我们可以在一个 _base.scss 中这么定义:
@mixin transition($content){ transition: $content;-webkit-transition: $content; -moz-transition: $content;-ms-transition: $content; }
然后在其它sass文件中import进来,以@include的形式使用:
@include transition(all .8s cubic-bezier(.15, .73, .37, 1.2));
YEP!就这么一句话搞定,妈妈再也不用操心我花时间复制粘贴改兼容代码了。
不过有时候transition里的特性也得加前缀啊,比如 -webkit-transition:-webkit-transform(XXX) 。傻孩纸,再封装一个方法就可以咯:
@mixin transition($content){ transition: $content;-webkit-transition: $content; -moz-transition: $content;-ms-transition: $content; } @mixin pTransition($content){ //内部特性也要加前缀的方法 -webkit-transition:-webkit-#{$content};-moz-transition:-moz-#{$content}; -ms-transition:-ms-#{$content};transition: $content; }
实际上我们要考虑的情况可能略复杂,但都不在sass话下,比如我在页面中经常复用一个translate3d和scale特性的样式定义,那么可以用sass这么包装:
@mixin scaleNt3d($x:1,$y:1,$a:0,$b:0,$c:0){ transform: scale($x,$y) translate3d($a,$b,$c); -webkit-transform: scale($x,$y) translate3d($a,$b,$c); -moz-transform: scale($x,$y) translate3d($a,$b,$c); -ms-transform: scale($x,$y) translate3d($a,$b,$c); }
综上可以知道,在css3动画模块的设计过程中,使用sass/less能极大提高你的工作效率、带来便捷。
动画处理
大部分的动画原理基本在我上篇文章优秀网站看前端 —— 小米Note介绍页面里说的七七八八了,主要思想无非还是 —— 先布局好动画最终效果,再添加translate3d等特性将其显示为动画起始的形态,然后通过窗口scroll到当前动画模块位置的时候给该模块加一个置空样式,把translate3d什么的效果统统清除掉,这样便也在transition的作用下动态展示了“清除样式”的过程。当然animation的形式也是同样原理。
比较棘手一些的还是window.onscroll事件卸载的处理吧,拿上述的产品介绍页来说,我是希望用户在看完三个选项卡的共8个动画之后,就直接off掉窗口的滚动事件。
于是拿下述代码来做处理:
function checkModule(){ var st = $win.scrollTop() + $win.height() - 300, pn = 'p' + flag; func[pn](); for(var i=0;i<arrs[pn].length;i++){ if(!arrs[pn][i] || st<arrs[pn][i]) continue; arrs['e'+flag][i].addClass('act'); arrs[pn][i] = null; if(i>=arrs[pn].length-1) arrs['f'+flag]=1 } if(arrs['f3'] && arrs['f2'] && arrs['f1']) $win.off('scroll',checkModule); }
其中 arrs 的初始模式如下:
arrs = {
p1:[], p2:[], p3:[],
e1:[], e2:[], e3:[]
}
pn用来push各动画模块的offset().top,en用来push各动画模块容器元素的JQ对象,窗体每滚动一次都会遍历对应的pn(通过flag识别用户在浏览哪个选项卡,从而遍历对应的pn和en)来判断窗体是否滚到了某个动画模块要被触发的位置,如果是,则给en加上触发动画的class。
每处理完en最后一个元素,就会给arrs加上对应的一个属性fn,然后在 if(arrs['f3'] && arrs['f2'] && arrs['f1']) 为真的时候卸下窗体的滚动监听。
另外在合作加盟页面做了个滚动视觉差效果(钱币会根据窗体滚动也上下滚动,没做太大幅度,可能得稍仔细看):
看着玄乎玄乎的,其实实现非常简单,跟h5和css3也没啥关系,无非在浏览器滚动的时候做判断和计算,给钱币一个对应的margin-top值:
//钱币视觉差滚动 var $win = $(window), purse_h = $("#purse").offset().top, step4_h = $("#step4").offset().top, $moneys = $('span','#intro3'), $m1 = $moneys.slice(0,3), $m2 = $moneys.slice(3,6), $m3 = $moneys.slice(6); $win.on("scroll",function(){ var h = $win.scrollTop() + $win.height(); if( (h <= purse_h) || ($win.scrollTop() > step4_h) ) return; $m1.css("marginTop",(purse_h-h)/5); $m2.css("marginTop",(purse_h-h)/15); $m3.css("marginTop",(purse_h-h)/20); });
其中的 purse_h 和 step4_h 分别是那个红色大钱袋以及下面那个“04加盟流程”容器距离文档顶部位置,窗体滚动的时候先判断是否在它们二者之间的区域内滚动,是的话才给钱币们(这里把11个钱币分为3个部分)做动画处理。
lazyload
这块主要针对首屏加载的优化,主要用于首页的幻灯片处,还有合作加盟页面。
拿合作加盟页面来说,有非常多的图片,篇幅也较长,等待这些图片的加载会消磨访问者的耐心。
于是我们不妨先加载首屏展示的图片,等DOMReady后再加载非首屏的图片:
我们把首屏的图片和其它部分图片区分为两部分的雪碧图(图1,图2),首屏的雪碧图做正常加载,其它部分要用到雪碧图的元素均加上一个class="lazyload"的类,用于脚本检索。
接着在DOMReady之后给这些元素添加设置了背景图片的class:
$(".lazyload").addClass('sprite-bg');
于是乎我们可以看到其它部分的雪碧图成功地延迟到最后下载:
总而言之懒加载的实现很简单,主要是需要有这样的优化思路,从小处着手。
资源压缩
新项目除了使用gulp常规化压缩脚本和样式外,也使用了gulp-imagemin 来优化图片大小(建议配合imagemin-pngquant使用):
从项目起始到现在,预计压缩掉超过1/3的图片体积。而且摆脱了手动去TinyPNG压缩图片的过程,也算是蛮大便利(也谢谢我这边的UI小欧妹子在PS中就先做了优化处理,特别是首页幻灯片和banner处基本都转为gif格式)。
其它
新版的站点不再使用旧版的bootstrap布局,提高渲染效率也减少冗余资源请求。也将把PC和移动端的版本分开为独立文件处理,不然像旧版那样混杂一起实在不便处理(也是旧版用bootstrap的原因),交互上也会被局限。
移动端版的仍处于UI设计过程中,后续会针对移动页面进行专版的优化,也打算把阿里的自适配技巧应用过来(前端只需按320的宽度做布局即可),以后有机会再跟大家分享。
另外在新版的站点上一共使用了俩款第三方字体,用的辅助工具是字蛛:
后续可能还会考虑走类似 r.js 打包项目的形式,以前会觉得这种形式略粗暴,不利于资源复用,但现在会觉得http连接建立的开销优化可能比资源复用更来的重要,有时间想玩玩jspm,据说包含了打包功能。
就唠嗑下这些有的没得,共勉~