检测属性是否可以通过 CSS3 转换进行动画处理?

发布于 2024-10-11 23:33:46 字数 209 浏览 2 评论 0原文

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

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

提前致谢!

The list of properties that can be animated with a CSS3 transition is not consistent among browsers and is a subject to change with new browser versions. For example, -moz-transform is not animatable with -moz-transition in FF3.6 but it is in FF4.

So, is there a way to detect in JavaScript if a particular property is animatable? I wouldn't like to use user agent sniffing as it's not reliable.

Thanks in advance!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

极度宠爱 2024-10-18 23:33:46

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

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

代码

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

如何使用

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

工作原理

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

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

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

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

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

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

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

Yes, there is a way. Demonstration follows, explanation below. There are some very important caveats involved, so make sure you read on.

The following code will test if the browser can animate between two values.

The code

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

How to use

The mandatory arguments for this are the property to animate and the starting and finishing values it should take. Optionally, you can pass an element with other initial styles set, e.g. position: absolute. (The function clones the element, so you can pass nodes from the document and they won't be changed.) If you don't pass any element, the animation is tested on a div with whatever default styles the UA applies.

How it works

A keyframe animation rule is added to a dummy stylesheet, with the initial frame set to the from value and the final frame set to the to value. This animation is applied to an element. We then inspect the computed style for the animated property to see if it is different when the animation starts from the initial frame compared to when it starts from the final frame.

The reason this works is because the animable properties for both transitions and keyframe animations are the same, and the browser will only apply keyframe values if the property supports animation.

Caveats (read before using, some of these are nasty!)

There are several inconsistencies in how browsers handle animations. A couple of these I have worked around in as future-proof a way as possible; however, a few of them are intractable.

Most notably, Firefox tweens position values (e.g. left) on static elements while others (e.g. Webkit and Opera) do not. It doesn't actually move the element, but the value of that property is updated. Thus, you will get different results between browsers if you try to animate a position value without passing a non-statically positioned element.

The most current versions of major browsers that support CSS transitions also support CSS keyframes, although some older versions support the former but not the latter. (E.g. Opera 11.)

Finally, if I were doing this more elegantly I would use prefixfree to determine the correct prefix to use directly; currently I test against an array of prefixes, starting with the unprefixed version.

无妨# 2024-10-18 23:33:46

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

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

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

Firefox 3.6 不支持 css 过渡,您可以使用 js 库检测这一点,例如Modernizr:

http://www.modernizr.com/

Edit: see Jordan's answer for a good technique on detecting animatable properties.

I'm afraid there is no straightforward way to detect if a property is animatable. However, the properties are consistent for the most part (the only problem I've encountered is with FF4 transition + text shadow + transform).

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

Firefox 3.6 doesn't support css transitions, you can detect this with a js library such as Modernizr:

http://www.modernizr.com/

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文