为什么我的CSS3 / jQuery动画的性能如此之慢?

时间:2011-11-05 02:08:23

标签: jquery css animation css3

为什么哦为什么这么慢?我用css3制作了一个等轴网格的立方体,它在鼠标悬停时上下摆动。它在Firefox上工作得很好,网格尺寸小于12,而且在大约18的情况下Chrome工作得很好。我有一个像样的视频卡和CPU,而且让我烦恼的是为什么只有一个立方体的动画制作动画这么慢如果我确保我只将鼠标移到一个立方体上。我的JavaScript需要优化还是仅仅是当前浏览器CSS3和JavaScript引擎的实现?下面的完整测试案例包括可以动态更改网格大小的滑块,既可以自己下载,也可以访问Doug提供的this jsfiddle version

<html>
    <head>
        <style type="text/css">
            body
            {
                background: black;
            }

            .cube
            {
                position: relative;
            }

            .cube .rightFace, .cube .leftFace
            {
                height: 25px; width: 10px; padding: 5px;
            }

            .leftFace
            {
                position: absolute;

                -webkit-transform: skew(0deg, 30deg);
                -moz-transform: skew(0deg, 30deg);
                -o-transform: skew(0deg, 30deg);

                -moz-box-shadow: rgba(0, 0, 0, 0.4) 1px 2px 10px;
                -webkit-box-shadow: rgba(0, 0, 0, 0.4) 1px 2px 10px;
                -o-box-shadow: rgba(0, 0, 0, 0.4) 1px 2px 10px;
                box-shadow: rgba(0, 0, 0, 0.4) 1px 2px 10px;

                border: 1px solid black;
            }

            .rightFace
            {
                -webkit-transform: skew(0deg, -30deg);
                -moz-transform: skew(0deg, -30deg);
                -o-transform: skew(0deg, -30deg);

                position: absolute;
                left: 19.5px;

                border: 1px solid black;
            }

            .topFace div
            {    
                width: 19px;
                height: 19px;


                border: 1px solid black;

                -webkit-transform: skew(0deg, -30deg) scale(1, 1.16);
                -moz-transform: skew(0deg, -30deg) scale(1, 1.16);
                -o-transform: skew(0deg, -30deg) scale(1, 1.16);
            }

            .topFace
            {
                position: absolute;

                left: 10.25px;
                top: -16.5px;

                -webkit-transform: rotate(60deg);
                -moz-transform: rotate(60deg);
                -o-transform: rotate(60deg);
            }

            #slider
            {
                width: 200px;
                margin: 0 auto;
            }
        </style>
        <link type="text/css" rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/base/jquery-ui.css" />
        <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
        <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/jquery-ui.min.js"></script>
        <script type="text/javascript">
            function refreshCubes()
            {
                $('.box').empty();
                var x = $("#slider").slider("value");
                var initialTop = 50;
                var initialLeft = 450;

                for(var i = 1; i < x; i++)
                {
                    for(var j = 1; j < x; j++)
                    {
                        var cube = $('<div class="cube"><div class="topFace"><div></div></div><div class="leftFace"></div><div class="rightFace"></div></div>');

                        cube.css(
                        {
                            left : initialLeft + (20 * i) + (-19 * j) + 'px',
                            top : initialTop + (11 * i) + (11 * j) + 'px'
                        });

                        cube.find('.topFace div').css('background', 'rgb(100,' + Math.ceil(255 - 16 * i) + ',' + Math.ceil(255 - 16 * j) + ')');
                        cube.find('.rightFace').css('background', 'rgb(35,' + Math.ceil(190 - 16 * i) + ',' + Math.ceil(190 - 16 * j) + ')');
                        cube.find('.leftFace').css('background', 'rgb(35,' + Math.ceil(190 - 16 * i) + ',' + Math.ceil(190 - 16 * j) + ')');
                        cube.children('div').css('opacity', '.9');

                        cube.hover(function()
                        {
                            $(this).animate({top: '-=25px'}, 400, 'easeInCubic');

                        }, function()
                        {
                            $(this).animate({top: '+=25px'}, 400, 'easeOutBounce');
                        });

                        $('.box').append(cube);
                    }
                }
            }

            $(document).ready(function()
            {    
                $('#slider').slider(
                {
                    value: 9,
                    max: 30,
                    min: 2,
                    slide: refreshCubes,
                    change: refreshCubes
                });

                refreshCubes();
            });
        </script>
    </head>
    <body>
        <div id="slider"></div>
        <div class="box"></div>
    </body>
</html>

3 个答案:

答案 0 :(得分:9)

这个更快:http://jsfiddle.net/JycdN/1/

我优化了jQuery代码本身。另外,设置动画“+ = 25px”样式CSS值是一个坏主意,因为每次执行此操作时,您都会强制浏览器在动画计算之外进行额外的CSS计算。您也可以使用纯CSS3动画,而不是这样做。看看这个:http://matthewlein.com/ceaser/

最好使animate()具有静态值(在这种情况下,我为data-属性中的每个多维数据集存储的原始位置和提升位置),因此唯一的计算是由javascript解释器本身。

live()方法会在重新创建时自动将事件添加到多维数据集,因此无需在refreshcubes函数内设置事件。此外,詹姆斯蒙塔尼指出,使用live()方法使整个事情像丹尼尔在他的答案中描述的那样(更快)。 编辑:使用on()方法代替live(),我的速度更快。悬停的事件上下文现在位于每个多维数据集上,而不是整个文档上。有关详细信息,请参阅此问题:How does jQuery's new on() method compare to the live() method in performance?

尽可能制作一个jquery对象并使用变量引用它,这样每次都不会重新创建一个新对象。

总体而言,我注意到性能有了相当大的提升,但它仍然比我想象的要慢。也许每次移动立方体时都会重新计算CSS变换(即使是像素)。

编辑:正如所添加的那样,修改jQuery.fx.interval有助于提高它的速度。

我认为在2D画布或3D webGL画布中绘制立方体会更加幸运。

尝试使用three.js或processing.js绘制立方体并为其设置动画。

编辑:我使用谷歌浏览器中的硬件加速CSS3动画更加快速(其他浏览器仍在开发这些CSS3功能,所以它现在仅适用于CHrome):http://jsfiddle.net/trusktr/JycdN/35/

答案 1 :(得分:3)

你有n ^ 2个听众,老实说惊讶的事情和他们一样有效。 Jquery没有足够的信息来优化算法,但我们做到了。而不是关心鼠标的位置n ^ 2次,我们实际上只需要检查一次。

为整个电路板添加一个监听器。随叫随到计算正在悬停的单元并为该单元设置动画。保持一个处于“开启”状态的单元格列表,并计算鼠标是否仍然悬停在它们上面,如果没有将它们设置为原始状态并将其从列表中删除。

现在代替n ^ 2操作,你拥有一个帧1.更多,但更快,代码和相同的功能。是的jquery很棒,不得不自己这样做是很可惜的。请记住,虽然jquery是为普通网站将使用的那些10个听众设计的,而不是100秒或1000秒。

@trusktr:它确实更快,但仍然比必要的慢很多倍。

答案 2 :(得分:3)

除了上面的优点之外,您还可以查看Jquery fx Interval。

http://api.jquery.com/jQuery.fx.interval/

默认情况下,动画间隔设置为13毫秒,大约每秒76帧。看起来很傻,所以将它设置为每秒20帧(50ms),可以提升性能。