javascript - 检测属性是否可以通过 CSS3 转换设置动画?

标签 javascript animation css transform transition

可以使用 CSS3 转换动画的属性列表在浏览器之间并不一致,并且可能会随着新浏览器版本的变化而变化。例如,-moz-transform 在 FF3.6 中不能与 -moz-transition 一起设置动画,但在 FF4 中可以。

那么,有没有一种方法可以在 JavaScript 中检测特定属性是否可以设置动画?我不想使用用户代理嗅探,因为它不可靠。

提前致谢!

最佳答案

是的,有办法。下面是演示,下面是解释。其中涉及一些非常重要的注意事项,因此请务必继续阅读。

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

代码

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 (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('-','');
};

使用方法

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

工作原理

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

之所以可行,是因为过渡动画和关键帧动画的可动画属性是相同的,如果属性支持动画,浏览器只会应用关键帧值。

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

浏览器处理动画的方式存在一些不一致之处。我以尽可能面向 future 的方式解决了其中的一些问题;然而,其中一些是棘手的。

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

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

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

关于javascript - 检测属性是否可以通过 CSS3 转换设置动画?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4679288/

相关文章:

java - 自定义 ImageView 从 ListAdapter 中消失

JQuery 跨浏览器性能 : . animate() on .hover() 超过 100 个 DOM 元素

谷歌地图方向的 html 代码不起作用

html - 帮我设计今天的日程表

html - 悬停时不会显示 Div

javascript - 将插入符号移动到焦点文本区域的末尾

javascript - 左侧表达式无效

IOS UITableview 如何在表格动画完成后采取行动

Javascript 的点击

javascript - 在 React 中将状态从子组件更新到父组件