简单的转盘抽奖——CSS动画优化

前言

前两天去一家公司面试,被问到一些小游戏的东西。面试官提到了刷红包还有抽奖这些怎么实现,当时简单说了下思路,回来之后想想还是说的太轻描淡写了,干说不做就是耍流氓,所以就做了一个(Demo & 源码)。启动方式:手指在转盘上滑动,转盘转动。这里没有像一般的抽奖程序一样在后台指定抽奖结果,结果完全由你的手速决定的(老板哭了。。。)

界面

界面很简单,网上搜个图片或者直接搜个 demo 就有了,当然自适应也是必须的。这里用了 Rem 来实现自适应,所有尺寸单位均用 rem,改变 html 节点的 font-size 即可实现全屏缩放,这里设置的是当屏幕宽度小于420px的时候转盘尺寸与屏宽城正比,当屏宽大于420px的时候转盘尺寸固定。更多关于rem实现自适应的内容,可以看看这里:Here

动效与交互

网上看到的demo大多数是点击启动的,就想着换个交互方式,用触屏滑动的方式启动。这里很容易就能想到以滑屏速度转动转盘,转动时给一个负加速度就可以实现减速了。这里要注意用户体验,为了让人有一个顺畅的感觉,启动的速度必须要相当的快,结尾的时候要慢慢的减速,营造抽奖的紧张气氛。所以加速度是有一个先大后小的变化,跟CSS中的 ease-out 一样的效果。代码如下:

var rotate = document.getElementById(‘imgs‘);
var speed = vspeed = 0,
    x0 = y0 = t0 = x1 = y1 = t1 = null;

(function(){
    var lastTime = 0;
    var vendors = [‘ms‘, ‘moz‘, ‘webkit‘, ‘o‘];
    for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x){
        window.requestAnimationFrame = window[vendors[x]+‘RequestAnimationFrame‘];
        window.cancelAnimationFrame = window[vendors[x]+‘CancelAnimationFrame‘] || window[vendors[x]+‘CancelRequestAnimationFrame‘];
    };

    if(!window.requestAnimationFrame){
        window.requestAnimationFrame = function(callback, element){
            var currTime = new Date().getTime();
            var timeToCall = Math.max(0, 16 - (currTime - lastTime));
            var id = window.setTimeout(function() { callback(currTime + timeToCall); }, timeToCall);
            lastTime = currTime + timeToCall;
            return id;
        };
    };

    if (!window.cancelAnimationFrame){
        window.cancelAnimationFrame = function(id){
            clearTimeout(id);
        };
    };
})(); // Setup requestAnimationFrame when it is unavailable.

document.addEventListener(‘touchmove‘, function (e) {
    e.preventDefault();
});

rotate.addEventListener(‘touchstart‘, function (e) {
    if (e.touches.length == 1) {
        x0 = e.targetTouches[0].clientX;
        y0 = e.targetTouches[0].clientY;
        t0 = new Date().getTime();
    }
});

rotate.addEventListener(‘touchend‘, function (e) {
    var that = this,
        l = 0,
        angle = 0,
        timerID = null;
    x1 = e.changedTouches[0].clientX;
    y1 = e.changedTouches[0].clientY;
    t1 = new Date().getTime();
    l = Math.sqrt(Math.pow(x1-x0,2) + Math.pow(y1-y0,2));
    speed = l/(t1-t0)*20;
    if (speed < 10) return;
    vspeed = 0.5;

    var roll = function () {
        angle += speed;
        that.style.transform = ‘rotateZ(‘ + angle + ‘deg)‘;
        switch (true){
            case speed < -0.3:
                window.cancelAnimationFrame(timerID);
                return;
            case speed < 10 && vspeed > 0.1:
                speed -= vspeed;
                vspeed -= 0.03;
                break;
            default:
                speed -= vspeed;
                break;
        }
        timerID = window.requestAnimationFrame(roll);
    };
    roll();
});

这里动画用的还是 h5 的 requestAnimationFrame 来实现,对于不支持 requestAnimationFrame 的浏览器也做了兼容。

编程还是相当简单的,难点在于参数的调整,要调整速度控制整个转动周期不能过长过短,而最麻烦的应该是最后减速阶段的加速度调整了。最后阶段太快了就没有紧张的气氛,太慢了又会有卡顿的感觉,尤其在国产移动浏览器上表现得更为明显。

性能优化

在没性能优化前,在国产的移动浏览器上卡顿得简直瞎了眼,优化是必须的。

常规做法:分层,动态元素与静态元素分离,也就是转盘绝对定位、单独占一个层,这样的话动态元素的变化不会影响到静态元素的布局,减少重绘。这个优化很基础,写页面的时候就已经实施了,可见问题并不在此。另外之前一直听说要用 CSS3d 变换的方法强制使用 GPU 渲染页面提高性能,但是代码上我已经写了 ‘rotateZ()‘,应该已经开启了硬件渲染了,不知道问题在哪,如何解决。空想也是无用,赶紧用 chrome developer 测试了一下:

可以看到数据其实还是相当不错的,脚本、渲染和绘图所占时间还比较合理的,但是问题会出在哪里呢?当然是国产浏览器身上了,那怎么去优化呢?再用 chrome 的渲染检测工具看看吧。打开方式:

  

见名知义,第一项可以检测页面的绘制刷新(重绘),第二项显示图层边界,第三项是显示 FPS(Frame per Second,FPS,帧率),这几项重点关注。因为这个是单页应用,所以后面的滚动问题检测和媒体仿真就略过了。启动之后是这样的:

  

最前面的绿色遮罩表示重绘区域,四周还有一圈褐色的表示渲染层,启动动画的时候可以发现在绘制动画时事实上转盘元素在不断重绘,这应该是问题的关键。但怎么解决呢?很多文章在介绍使用 GPU 渲染时候都会提到下面这两句样式:

backface-visibility: hidden;
perspective: 1000;

试着用了这两句之后,立马出现了效果,旋转的时候不再出现绿色的重绘框了:

再回到某国产移动浏览器上测试,终于没有那种死活转不起来的感觉了,感觉跟原生应用差不多了,其实原生应用无非也是用了 GPU 渲染而已,当 web 能调用这些底层的话,性能上差别不会很大。这里面其实后面一句 perspective: 1000; 是多余的,设这么大的透视距离目的是为了减弱 3D 效果,减少计算量,而转盘转动本来就没 3D 效果,所以这里是没效果的。

主要是 backface-visibility: hidden 起作用。backface 就是元素背面,元素和医院照的X光片一样,正反两面都可以看。隐藏背面的意思就是转过来是空白的,什么也没有。如果不设置这个的话,浏览器会连物体的背面也渲染出来。由于转盘元素上面还叠加有指针元素,如果不指定隐藏背面的话,那浏览器就将转盘覆盖的范围全部重绘,比如说我绕 X 或者 Y 轴旋转,既然画出转盘还要画出指针,那肯定是要重绘这一大块页面的。至于隐藏背面之后为何不再发生渲染层的重绘,这个可能跟浏览器的渲染策略有关,这里浏览器应该会按照最优解去重绘所需的层,不变的层仍然保留,最后做合成算法。这一块我也还不甚了解,这些只是我个人的理解,有不当之处请务必指正!

PS: 后续发现只要设置了 backface-visibility: hidden,根本不需要开启 GPU,直接用 2D 旋转也能得到非常好的效果!

邓爷爷说得对,实践是检验真理的唯一标准!

参考资料:

1)Accelerated Rendering in Chrome: http://www.html5rocks.com/en/tutorials/speed/layers/

2)App performance validation: https://developer.mozilla.org/en-US/Apps/Fundamentals/Performance/App_performance_validation

3)被解放的GPU CSS3动画加速: http://www.cnblogs.com/sunshq/p/4878019.html

4)【Web动画】CSS3 3D 行星运转 && 浏览器渲染原理: http://www.cnblogs.com/coco1s/p/5439619.html#3420358

5)Web animations on large screens: https://developer.mozilla.org/zh-CN/docs/Mozilla/Firefox_OS_for_TV/Web_animations_on_large_screen

以上,码字不易,随手点赞哈

(图片出处:小周)

 原创文章,转载请注明出处!本文链接:http://www.cnblogs.com/qieguo/p/5481522.html 

时间: 2024-10-07 22:21:26

简单的转盘抽奖——CSS动画优化的相关文章

前端性能优化(css动画篇)

正巧看到在送书,于是乎找了找自己博客上记录过的一些东西来及其无耻的蹭书了~~~ 小广告:更多内容可以看我的博客 最近拜读了一下html5rocks上几位大神写的一篇关于CSS3动画性能优化的文章,学到了很多,在这里记录一下,其中的知识都是来源于这俩篇文章,我只是截取了其中比较关注的内容出来,原文地址High Performance Animations及Accelerated Rendering in Chrome 原理 现代浏览器在使用CSS3动画时,以下四种情形绘制的效率较高,分别是:* 改

前端性能优化 CSS动画

最近拜读了一下html5rocks上几位大神写的一篇关于CSS3动画性能优化的文章,学到了很多,在这里记录一下,其中的知识都是来源于这俩篇文章,我只是截取了其中比较关注的内容出来,原文地址High Performance Animations及Accelerated Rendering in Chrome 原理 现代浏览器在使用CSS3动画时,以下四种情形绘制的效率较高,分别是: * 改变位置 * 改变大小 * 旋转 * 改变透明度 层?重绘?回流和重布局?图层重组? 首先要了解CSS的图层的概

web前端入门到实战:css动画优雅降级的简单总结

CSS动画优雅降级的简单总结 CSS动画相关属性 transition:兼容性 transform 3D:兼容性 transform 2D:兼容性 animation: 可以看到动画在IE8(这里主要讨论IE)及以下完全不支持,IE9由于只支持transform(非transform3d) 优雅降级 <div class="a"></div> CSS: web前端开发学习Q-q-u-n: ××× ,分享学习的方法和需要注意的小细节,不停更新最新的教程和学习方法(

Es6语法实现的转盘抽奖效果——可配置转盘的抽奖概率

最近公司要做一个转盘抽奖的效果,但是我们可以控制转盘抽奖的概率,自己用es6简单的实现了下,中间虽然遇到一些问题,但最终都是解决了,下面说一下我的思路. <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <link rel="stylesheet" href="css/index.css">

纯CSS3大转盘抽奖(响应式、可配置)

源于前段时候微信小程序最初火爆公测时段,把以前用 Canvas 实现的大转盘抽奖移植成微信小程序,无奈当时小程序对 Canvas 支持不够完善,只好降低用 CSS3 实现.虽然比不上 Canvas 绘图的绚丽,但也总算完成了一个抽奖的 Demo,详见:https://github.com/givebest/wechat-turntalbe-canvas. 事后想起,CSS3 实现也并不是无有益处,比如简单.快捷.调试方便.渲染想来也是要比 Canvas 要高效的,更重要的一点是支持媒体查询,大转

CSS动画与GPU

写在前面 满世界的动画性能优化技巧,例如: 只允许改变transform.opacity,其它属性不要动,避免重新计算布局(reflow) 对动画元素应用transform: translate3d(0, 0, 0).will-change: transform等,开启硬件加速 动画元素尽量用fixed.absolute定位方式,避免reflow 对动画元素应用高一点的z-index,减少复合层数量 ...其它可能有用的规则 那么问题是:已经小心遵守这些规则了,为什么动画还会卡顿.跳帧?还能优化

运动曲线提升CSS动画效果

原文链接 译文\译者鞠大宝 先有UI动画,然后才会有好的UI动画.好的动画会让人惊叹“哇哦!”——因为页面看上去很流畅.很漂亮,最重要的是,自然,一点都不会让人觉得不和谐或者僵硬死板.如果你经常逛Dribbble或者 UpLabs这类网站的话,你就会明白我在说什么了. 一些极好的拓展阅读资源: ·SVG和CSS的路径剪辑动画 ·若干实用的动画技术 ·使用SVG手绘动画 ·新的网页动画API 既然有这么多天才设计师创造了如此漂亮的动画,自然是任何开发者都会想要在自己的项目中引进这些效果.如今,CS

无线页面动画优化实例

无线页面本就分秒必争,更不用说当我们在无线页面中使用动画的时候.不管是css动画还是canvas动画,我们都需要时刻小心着,并且有必要掌握页面性能的基本分析方法. 既然我们的目标是优化,那么就与浏览器的一些渲染和执行机制有关,更好的迎合浏览器的行为方式,才可以让我们的动画流畅而优美. 没错,浏览器是老大,全听它的. 一.设备刷新率(帧率) 我们想让页面变快,想让动画流畅,我们需要先了解一下是什么在影响着我们的感知. 页面运行在设备的浏览器中,现在市面上的移动设备的刷新频率大多是60次/秒(帧率)

java实现转盘抽奖;

index.jsp页面: <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme() + "://" + request.getServerName() + ":