检测属性是不是可以通过 CSS3 过渡设置动画?

Posted

技术标签:

【中文标题】检测属性是不是可以通过 CSS3 过渡设置动画?【英文标题】:Detect if property is animatable by CSS3 transition?检测属性是否可以通过 CSS3 过渡设置动画? 【发布时间】:2011-06-08 10:26:17 【问题描述】:

可以使用 CSS3 过渡进行动画处理的属性列表在浏览器之间并不一致,并且会随着新浏览器版本的变化而变化。例如,-moz-transform 在 FF3.6 中无法使用 -moz-transition 进行动画处理,但在 FF4 中却可以。

那么,有没有办法在 javascript 中检测特定属性是否可动画化?我不想使用用户代理嗅探,因为它不可靠。

提前致谢!

【问题讨论】:

【参考方案1】:

是的,有办法。演示如下,解释如下。涉及到一些非常重要的警告,因此请务必继续阅读。

以下代码将测试浏览器是否可以在两个值之间进行动画处理。

代码

jsFiddle demo.

/*
@param property  The property to test.
@param from      A valid starting value for the animation.
@param to        A valid ending value for the animation.
@param [element] The element to test with. (Required for testing
                 properties with prerequisites, e.g. "top" requires
                 non-static position.)
*/
function isAnimationSupported(property, from, to, element) 
    var doc = document.documentElement,
        style = doc.appendChild(document.createElement("style")),
        rule = [
                'capTest',
                    '0%',   property, ':', from, '',
                    '100%', property, ':', to,   '',
                ''
               ].join(''),
        propCamel = property.toCamelCase(),
        prefixes = 'moz ms o webkit '.split(' '), // Unprefixed last, see comments.
        prefixCount = prefixes.length,
        canAnimate = false;

    element = doc.appendChild((element)
            ? element.cloneNode(false)
            : document.createElement('div'));

    // Detect invalid start value. (Webkit tries to use default.)
    element.style[propCamel] = to;

    // Iterate through supported prefixes.
    for (var i = 0; i < prefixCount; i++) 

        // Variations on current prefix.
        var prefix  = prefixes[i],
            hPrefix = (prefix) ? '-' + prefix + '-' : '',
            uPrefix = (prefix) ? prefix.toUpperCase() + '_' : '';

        // Test for support.
        if (Cs-s-rule[uPrefix + 'KEYFRAMES_RULE']) 

            // Rule supported; add keyframe rule to test stylesheet.
            style.sheet.insertRule('@'+ hPrefix + 'keyframes ' + rule, 0);

            // Apply animation.
            var animationProp = (hPrefix + 'animation').toCamelCase();
            element.style[animationProp] = 'capTest 1s 0s both';

            // Get initial computed style.
            var before = getComputedStyle(element)[propCamel];

            // Skip to last frame of animation.
            // BUG: Firefox doesn't support reverse or update node style while
            // attached.
            doc.removeChild(element);
            element.style[animationProp] = 'capTest 1s -1s alternate both';
            doc.appendChild(element);
            // BUG: Webkit doesn't update style when animation skipped ahead.
            element.style[animationProp] = 'capTest 1s 0 reverse both';

            // Get final computed style.
            var after = getComputedStyle(element)[propCamel];

            // If before and after are different, property and values are animable.
            canAnimate = before !== after;
            break;
        
    

    // Clean up the test elements.
    doc.removeChild(element);
    doc.removeChild(style);

    return canAnimate;


// Cribbed from Lea Verou's prefixfree.
String.prototype.toCamelCase = function() 
    return this.replace(/-([a-z])/g, function($0, $1)  return $1.toUpperCase(); )
               .replace('-','');
;

如何使用

对此的强制参数是动画的属性以及它应该采用的开始和结束值。或者,您可以传递具有其他初始样式集的元素,例如position: absolute。 (该函数克隆元素,因此您可以从文档中传递节点并且它们不会被更改。)如果您不传递任何元素,则动画将在 div 上使用 UA 应用的任何默认样式进行测试。

工作原理

将关键帧动画规则添加到虚拟样式表中,初始帧设置为from 值,最终帧设置为to 值。此动画应用于元素。然后,我们检查动画属性的计算样式,以查看动画从初始帧开始与从最终帧开始时的样式是否不同。

之所以可行,是因为转场动画和关键帧动画的可动画属性是相同的,并且只有在属性支持动画时,浏览器才会应用关键帧值。

注意事项(使用前请阅读,其中一些很讨厌!)

浏览器处理动画的方式有几个不一致的地方。其中一些我已经以尽可能面向未来的方式解决了;但是,其中一些是棘手的。

最值得注意的是,Firefox 补间位置值(例如 left)在静态元素上,而其他(例如 Webkit 和 Opera)则没有。它实际上并没有移动元素,而是更新了该属性的值。因此,如果您尝试在不传递非静态定位元素的情况下为位置值设置动画,则会在浏览器之间得到不同的结果。

支持 CSS 过渡的主流浏览器的最新版本也支持 CSS 关键帧,尽管一些旧版本支持前者但不支持后者。 (例如 Opera 11。)

最后,如果我这样做更优雅,我会使用prefixfree 来确定要直接使用的正确前缀;目前我针对一组前缀进行测试,从无前缀版本开始。

【讨论】:

+1 非常酷!它在top right left bottom 上给出错误,因为测试 div 不是绝对定位的。我不知道如何处理这个问题,也许你可以传递一个元素来覆盖测试 div? 好点!添加一个可选的元素参数似乎是个好主意;当我的宽带死机时,我实际上已经更新了小提琴。等我重新上线再更新说明! :) 酷!另一个很好的测试是对内联元素进行动画 css 转换,这应该会失败。 @Duopixel 哦,伙计。我对其工作方式进行了一些重大更改,但请特别注意注意事项。 tl;dr:Firefox 在静态元素上补间位置属性。另请注意,both 浏览器对内联元素的变换矩阵进行补间,因此对于内联元素和块元素的动画变换,它都会返回正值。从好的方面来说,更新后的版本会告诉您是否可以在两个属性之间进行补间,因此在例如返回 false从像素值动画到百分比值时的 Webkit。 这太奇怪了。转换不适用于带有内联元素的 Web 检查器中的计算样式。我试试看。【参考方案2】:

编辑:请参阅 Jordan's answer 了解检测动画属性的好方法。

恐怕没有直接的方法来检测属性是否可动画。但是,大部分属性是一致的(我遇到的唯一问题是 FF4 过渡 + 文本阴影 + 变换)。

http://www.w3.org/TR/css3-transitions/#the-transition-property-property-#properties-from-css-

Firefox 3.6 不支持 css 过渡,您可以使用 Modernizr 等 js 库来检测:

http://www.modernizr.com/

【讨论】:

谢谢!我确信有一些稳定版本的 FF,其中有没有动画变换的过渡支持,但事实证明这是在一些 FF4 测试版中,现在一切似乎都很好。 我一直在为另一个项目考虑这个问题,这实际上是可能的——见下文。 :)

以上是关于检测属性是不是可以通过 CSS3 过渡设置动画?的主要内容,如果未能解决你的问题,请参考以下文章

重新想,重新看——CSS3变形,过渡与动画③

CSS3动画2D3D转换

css3的过渡和动画的属性介绍

CSS如何实现动画?

如何触发css3过渡动画

前端学习(18)~css3属性学习:动画详解