通过CSS3过渡检测属性是否可动画?

Mou*_*ner 5 javascript animation transition transform css3

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

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

提前致谢!

Jor*_*ray 9

是的,有一种方法.演示如下,解释如下.有一些非常重要的注意事项,所以请务必继续阅读.

以下代码将测试浏览器是否可以在两个值之间设置动画.

代码

jsFiddle演示.

/*
@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 (CSSRule[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('-','');
};
Run Code Online (Sandbox Code Playgroud)

如何使用

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

这个怎么运作

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

这样做的原因是因为过渡和关键帧动画的可动画属性是相同的,并且浏览器将仅在属性支持动画时应用关键帧值.

注意事项(使用前阅读,其中一些是令人讨厌的!)

浏览器处理动画的方式有几处不一致.其中一些我已经尽可能地以未来的方式解决了这个问题; 然而,其中一些是难以处理的.

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

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

最后,如果我更优雅地这样做,我会使用prefixfree来确定直接使用的正确前缀; 目前我测试了一系列前缀,从未加前缀的版本开始.


met*_*ion 3

编辑:请参阅乔丹的答案,了解检测可动画属性的好技术。

恐怕没有直接的方法来检测属性是否可动画。然而,大部分属性是一致的(我遇到的唯一问题是 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/