优秀网站看前端 —— 小米Note介绍页面

刚开始经营博客的时候,我写过很多“扒皮”系列的文章,主要介绍一些知名站点上有趣的交互效果,而后试着实现它们。后来开始把注意力挪到一些新颖的前端技术上,“扒皮”系列便所以封笔多时。今天打算重开“扒皮”的坑,不过咱挂个优雅点的名字——“优秀网站看前端”,顾名思义的,也是寻觅一些值得玩味的趣味网站,来学习它们的前端技术和交互理念。css

做为本系列的开篇,咱们拿“买手机送国土”的小米来打头阵,原因是鄙人有着更换手机的打算又恰好看上小米note高配版,因而逛了下小米note的介绍页面,感受交互作的挺不错,特别是CSS3动画部分,不妨就直接写篇文章和你们一同来学习和分享。html

小米note的介绍页面地址以下,你们能够先去领略它的交互效果:前端

http://www.mi.com/minote/node

字体css3

该网站首先吸引个人是其在标题头等地方使用的字体,因为自己也喜欢搞设计,因此一眼就注意到这两行细体字绝非宋体黑体和雅黑,check了一下,字体名为FZLTXHK(也就是方正兰亭纤黑体)web

会不会有点小诧异,常规咱们是很不推荐在网页上经过font-face来引入第三方中文字体的,毕竟一个完整的中文字体包常规都是好几M的大小,一来得让客户端花时间请求、浪费用户流量,二来会形成页面字体效果切换的闪动(FOUT——flash of unstyled text)现象。gulp

小米做为一个注重用户体验的公司,相信也不会作这么不合常理的事情(喂,没打算聊国土啊喂)。那么字体这块,小米天然也是动了些手脚——只封装了页面上须要使用到的文字。不信?你能够试着把用到第三方字体的标题内容更改成其它内容,你会发现不少文字是不被该字体所支持的:浏览器

那么小米的射鸡狮真是辛苦,每次修改页面都要手动打包新的字体,真是兢兢业业可歌可泣。。。。其实未然,毕竟如今不是刀耕火种的原始社会,咱们能够直接请node包加持~ide

因而 “字蛛(FontSpider)” 这款工具能够粉墨登场啦(别乱用成语啊亲~)—— 字蛛经过分析本地 CSS 与 HTML 文件获取 WebFont 中没有使用的字符,并将这些字符数据从字体中删除以实现压缩,同时生成跨浏览器使用的格式。svg

字蛛的使用方式在其官网上已经解释的很清楚了,本文不赘述,但先聊聊@font-face的匹配格式,也就是聊一聊WEB上经常使用的字体格式。

@font-face中引入的字体文件能够经过format方法来帮助浏览器匹配到对应的字体格式,常规各浏览器所支持的字体格式有以下几种:

1、TureTpe(.ttf)格式:

.ttf字体是Windows和Mac的最多见的字体,是一种RAW格式,所以他不为网站优化,支持这种字体的浏览器有(IE9+,Firefox3.5+,Chrome4+,Safari3+,Opera10+,iOS Mobile Safari4.2+);

2、OpenType(.otf)格式:

.otf字体被认为是一种原始的字体格式,其内置在TureType的基础上,因此也提供了更多的功能,支持这种字体的浏览器有(Firefox3.5+,Chrome4.0+,Safari3.1+,Opera10.0+,iOS Mobile Safari4.2+);

3、Web Open Font Format(.woff)格式:

.woff字体是Web字体中最佳格式,他是一个开放的TrueType/OpenType的压缩版本,同时也支持元数据包的分离,支持这种字体的浏览器有(IE9+,Firefox3.5+,Chrome6+,Safari3.6+,Opera11.1+);

4、Embedded Open Type(.eot)格式:

.eot字体是IE专用字体,能够从TrueType建立此格式字体,支持这种字体的浏览器有(IE4+);

5、SVG(.svg)格式:

.svg字体是基于SVG字体渲染的一种格式,支持这种字体的浏览器有(Chrome4+,Safari3.1+,Opera10.0+,iOS Mobile Safari3.2+)。

 

那么综上所述,一个@font-face只要匹配了.eot 和 其它某种字体(最好是.woff),就基本能在大多数浏览器上正常显示了。不过查看小米的样式(点我查看),它只匹配了.woff(也就是IE8-将降级为常规字体)。另外,小米将该字体文件以base64编码形式直接inline在css上,此举有个好处——减小了一次文件请求,也能有效防止上文提过的FOUT现象。

不过这个base64怎么折腾出来的?或许小米用字蛛之类的工具得到字体压缩文件后,再经过某种方式(好比在这里转换)将其转为base64编码形式便可。

另外小米还使用了一个CSS3样式:

-webkit-font-smoothing:antialiased

该属性可使页面上的字体抗锯齿,使用后字体看起来会更清晰舒服(特别适用于字号较小的文本内容)。

有三种可选值:

none | subpixel-antialiased | antialiased

它们的区别见下图:

transition动画

小米的页面处处都充满了视觉差滚动效果,有种随时给你小惊喜的感受:

如上图的动画,是由transition实现的,大体步骤以下:

⑴ 给全部要动画的元素设置transition属性,好比 transition:transform 1s

⑵ 给全部动画元素添加一个class="visible" ,该class中定义了动画的最终状态;

⑶ 页面DOMReady的时候遍历全部动画元素($(".visible")),检查它们是否还没被滚动条滚上来,若是还在窗口可视区域下方,则移除它们"visible"的class。该步骤主要是用于处理用户下拉页面到某个位置而后刷新页面,这时要求窗口可视区域及其上方的元素都应跳过动画的状态,直接到达动画最终状态;

⑷ 监听onscroll事件,移动到某个动画元素的位置时,则移除该元素名为"visible"的class。

咱们能够粗略地写个场景和脚原本实现:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>动画模拟</title>
    <script src="jq.js"></script>
    <style>
        article,div{margin: 380px 0;border: solid 1px gray;}
        article > section{width:50px;height:50px;background:red;transform: translate3d(-100px, -60px, 0);opacity: 0;transition: all .8s;}
        article > section.visible {transform: translate3d(0, 0, 0);opacity: 1;}

        div > span{background:blue;transform: scale(.2);opacity: 0;transition: all 2s;}
        div > span.visible {transform: scale(1);opacity: 1;}

        div > p {width:50px;height:50px;background:yellow;transform: translate3d(90px, 100px, 0);opacity: 0;transition: all 1.5s;}
        div > p.visible {transform: translate3d(0, 0, 0);opacity: 1;}
    </style>
    <script>
        $(function(){
            var elmArr = [],
                $win = $(window);
            $(".visible").each(function(i,elm){
                $(elm).data("ot",$(elm).offset().top);
                elmArr.push(elm);
            });

            dealClass(1);
            $win.on("scroll",dealClass);

            function dealClass(isRemove){
                var top = $win.height() + $win.scrollTop();
                if(isRemove!=1) { //滚动页面时的判断,并添加class="visible"
                    for (var i = 0,$elem; i < elmArr.length; i++) {
                        $elem = $(elmArr[i]);
                        if ($elem.data("ot") <= top) {
                            $elem.addClass("visible");
                            elmArr.splice(i, 1);
                            --i;
                        }
                    }
                }else{  //初始化页面时的判断,并删除class="visible"
                    for (var i = 0,$elem; i < elmArr.length; i++) {
                        $elem = $(elmArr[i]);
                        if ($elem.data("ot") >= top) {
                            $elem.removeClass("visible");
                        }
                    }
                }
            }
        })
    </script>
</head>
<body>
<article>
    <section class="visible"></section>
</article>
<div>
    <span class="visible">hello</span>
</div>
<div>
    <p class="visible"></p>
</div>
</body>
</html>

效果以下:

transition动画效果默认是线性展现的(linear),咱们经过设置其timing-function属性可让效果变得更灵活,好比这个效果:

此处的transition-timing-function属性被设置为 cubic-bezier(.15, .73, .37, 1.2) ,表示按照该贝塞尔曲线函数来执行动画(了解更多请戳我

你能够试着把咱们上方例子中的 transition:XXX 修改成:

 transition: transform 1.5s cubic-bezier(.15, .73, .37, 1.2),opacity 1s;

而后查看其效果:

若是在transition的最后加上一个时间单位,能够延迟触发动画效果。好比上面五个手机(5个<li>标签)是按顺序依次出来的,那么咱们能够给第2个<li>设定0.2秒的延迟,给第3个<li>设定0.4秒的延迟,给第4个<li>设定0.6秒的延迟。。。

咱们拿第2个<li>的transition来示例:

transition:transform 1s cubic-bezier(.15, .73, .37, 1.2) .2s;

因为在末尾写上了0.2s的transition-delay值,故第二个手机会相较第一个手机晚0.2秒执行动画。

animate动画

animate很适用于那些须要分段展现的,或者有周期性的非过渡性动画,好比双4G的介绍区域就使用了animate(该效果页面地址

该卡槽是由一个div(卡槽自己)内嵌一个span(最后淡入显示的镂空处文本)组成的,div触发动画时(跟transition同样加个触发class)直接从下往上显示(2s),而span虽然是同时被触发动画,但它延迟2s才执行,因此营造了“在div动画结束后,span才开始触发动画”的视觉效果。

咱们照样拿前面的例子来修改:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>动画模拟</title>
    <script src="jq.js"></script>
    <style>
        body,html{height: 100%;}
        @-webkit-keyframes ani-fade-in {
            0% {
                opacity: 0
            }
            100% {
                opacity: 1
            }
        }
        @keyframes ani-fade-in {
            0% {
                opacity: 0
            }
            100% {
                opacity: 1
            }
        }
        @-webkit-keyframes ani-fade-in-up {
            0% {
                -webkit-transform: translateY(100px);
                opacity: 0
            }
            100% {
                -webkit-transform: translateY(0);
                opacity: 1
            }
        }
        @keyframes ani-fade-in-up {
            0% {
                -webkit-transform: translateY(100px);
                opacity: 0
            }
            100% {
                -webkit-transform: translateY(0);
                opacity: 1
            }
        }

        article{margin: 500px 0;}
        div{width:50px;height:50px;background:green;opacity: 0;}
        div.visible{-webkit-animation:ani-fade-in-up 2s ease forwards;animation:ani-fade-in-up 2s ease forwards;}
        div > span{background:blue;opacity: 0;}
        div.visible > span {-webkit-animation:ani-fade-in 1s 2s ease forwards;animation:ani-fade-in 1s 2s ease forwards;}

    </style>
    <script>
        $(function(){
            var elmArr = [],
                $win = $(window);
            $(".visible").each(function(i,elm){
                $(elm).data("ot",$(elm).offset().top);
                elmArr.push(elm);
            });

            dealClass(1);
            $win.on("scroll",dealClass);

            function dealClass(isRemove){
                var top = $win.height() + $win.scrollTop();
                if(isRemove!=1) { //滚动页面时的判断,并添加class="visible"
                    for (var i = 0,$elem; i < elmArr.length; i++) {
                        $elem = $(elmArr[i]);
                        if ($elem.data("ot") <= top) {
                            $elem.addClass("visible");
                            elmArr.splice(i, 1);
                            --i;
                            if(i<0) $win.off("scroll",dealClass);
                        }
                    }
                }else{  //初始化页面时的判断,并删除class="visible"
                    for (var i = 0,$elem; i < elmArr.length; i++) {
                        $elem = $(elmArr[i]);
                        if ($elem.data("ot") >= top) {
                            $elem.removeClass("visible");
                        }
                    }
                }
            }
        })
    </script>
</head>
<body>
<article>
    <section>123</section>
</article>
<div class="visible">
    <span>hello</span>
</div>
</body>
</html>
View Code

效果以下:

其实这段代码中涉及动画的最关键的部分不外乎这两行:

div.visible{-webkit-animation:ani-fade-in-up 2s ease forwards;animation:ani-fade-in-up 2s ease forwards;}
div.visible > span {-webkit-animation:ani-fade-in 1s 2s ease forwards;animation:ani-fade-in 1s 2s ease forwards;}

其中span动画延迟2秒执行,执行过程为1s,另外二者都使用了forwards来保持最终状态。

另外在介绍wifi的地方还有一个有趣的循环动画:

这是在animation中将其动画执行次数设置为infinite :

@-webkit-keyframes ani-circle-scale {
    0% {
        -webkit-transform: scale(0);
        margin-left: 0
    }
    45% {
        -webkit-transform: scale(1);
        margin-left: -999px;
        opacity: 1
    }
    80% {
        opacity: 1
    }
    100% {
        opacity: 0
    }
}

div{-webkit-animation:ani-circle-scale 8s ease-out forwards infinite;}

更多animation的知识点可点此查阅。

其它

相机介绍页面,小米还使用了video来展现一个小动画(有些复杂点的展现效果直接使用小尺寸的视频来展现也是个不错的选择)

此处代码为:

<video id="exporevideo" poster="http://img03.mifile.cn/webfile/images/2014/cn/goods/minote/camera/ca-49.png">
     <source src="http://img03.mifile.cn/webfile/images/2014/cn/goods/minote/camera/jingtou.mp4" type="video/mp4">
     <source src="http://img03.mifile.cn/webfile/images/2014/cn/goods/minote/camera/jingtou.webm" type="video/webm">
     <img src="http://img03.mifile.cn/webfile/images/2014/cn/goods/minote/camera/ca-49.png" alt="">
 </video>

两个source分别匹配了mp4和webm格式的视频文件,其中mp4是为了兼容IE9+和Safari,webm是为了兼容旧版的Firefox和Opera。除了mp4和webm,其实还有ogg格式可选,各浏览器对视频格式的支持度可查看维基百科(很是详尽)

最后的那张img图片是用来优雅降级的,也就是不支持<video>标签的浏览器会直接显示为这张图片。

小米在其基础样式中还对全体img使用了 -ms-interpolation-mode:bicubic  属性,它可让IE下被缩小的图片保持较高质量,而不是变得模糊、带锯齿。不过该样式其实只对IE7有做用,由于IE8+的缺省值已设定为bicubic(IE7-下为nearest-neighbor ,图片被缩放后质量会不好)

另外小米对其样式和脚本均作了混淆和压缩处理,不过这已不是什么新奇的东西,只是使用了 gruntgulp 等前端辅助工具罢了。

本篇就介绍到这里,实际上小米官网上还有不少本章未说起的有趣交互,有兴趣的朋友能够去仔细摸索一番。

话说最近也是蛮拼的,博客越写越长、越写越晚,醉了。。。

共勉~

donate

相关文章
相关标签/搜索