• 谈谈石豆官网改版的前端优化


    (注:本人现已不在石豆任职,且石豆官网又进行了一次新的改版,故本文章内容已不再匹配石豆现有官网)

    这俩星期主要致力于公司官网的改版,今天也算是比较完整地上线(暂时还是全静态的),可以在 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>
    View Code


    而在其它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,据说包含了打包功能。

    就唠嗑下这些有的没得,共勉~

    donate

  • 相关阅读:
    Spring-Cloud 学习笔记-(4)负载均衡器Ribbon
    Spring-Cloud 学习笔记-(5)熔断器Hystrix
    微信支付(APP)
    Resetting Frame Animation
    Java内部类与final关键字详解
    UML中关联(Association)和依赖(Dependency)的区别
    ListView 介绍
    android Activity类中的finish()、onDestory()和System.exit(0) 三者的区别
    AsyncTask和Handler对比
    create groups 和 create folder reference
  • 原文地址:https://www.cnblogs.com/vajoy/p/4431697.html
Copyright © 2020-2023  润新知