2011-01-13 4 views
4

Die Liste der Eigenschaften, die mit einem CSS3-Übergang animiert werden können, ist unter den Browsern nicht konsistent und kann sich mit neuen Browserversionen ändern. Zum Beispiel ist -moz-transform in FF3.6 nicht mit -moz-Übergang animierbar, aber in FF4.Erkennen, ob Eigenschaft durch CSS3-Übergang animierbar ist?

Gibt es also eine Möglichkeit, in JavaScript zu erkennen, ob eine bestimmte Eigenschaft animierbar ist? Ich möchte nicht User Agent Sniffing verwenden, da es nicht zuverlässig ist.

Vielen Dank im Voraus!

+2

@Mourner Es wäre rad, wenn Sie meine Antwort nicht akzeptieren und Jordan akzeptieren würde, nur für Leute, die diese Art von Sachen googlen. – Duopixel

Antwort

3

Bearbeiten: siehe Jordan's answer für eine gute Technik beim Erkennen animierbare Eigenschaften.

Ich fürchte, es gibt keine direkte Möglichkeit zu erkennen, ob eine Eigenschaft animierbar ist. Die Eigenschaften sind jedoch größtenteils konsistent (das einzige Problem, das ich festgestellt habe, ist FF4-Übergang + Textschatten + Transformation).

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

Firefox 3.6 nicht CSS-Übergänge unterstützen, können Sie dies mit einer js Bibliothek wie Modernizr erkennen:

http://www.modernizr.com/

+0

Danke! Ich war mir sicher, dass es eine stabile Version von FF gab, wo es eine Übergangsunterstützung ohne animierbare Transformation gab, aber es stellte sich heraus, dass dies in einigen FF4-Betas war und jetzt scheint alles in Ordnung zu sein. – Mourner

+0

Ich habe darüber nachgedacht für ein anderes Projekt, und es ist tatsächlich möglich - siehe unten. :) –

7

Ja, es ist ein Weg. Demonstration folgt, Erklärung unten. Es gibt einige sehr wichtige Vorbehalte beteiligt, so stellen Sie sicher, dass Sie weiter lesen.

Der folgende Code wird testen, ob der Browser zwischen zwei Werten animieren kann.

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

Wie für diese

Die obligatorischen Argumente zu verwenden sind Eigentum zu animieren und die Start- und Zielwerte es dauern sollte. Optional können Sie ein Element mit anderen Anfangsstilen übergeben, z. position: absolute. (Die Funktion klont das Element, so dass Sie Knoten aus dem Dokument übergeben können und diese nicht geändert werden.) Wenn Sie kein Element übergeben, wird die Animation unter Verwendung von div mit allen Standardstilen getestet, auf die das UA angewendet wird.

Wie es

Eine Keyframe-Animation Regel arbeitet an ein Dummy Sheet hinzugefügt, mit dem Anfang zum from Wert und der letzten Frame auf den to Wert gesetzt Rahmen. Diese Animation wird auf ein Element angewendet. Wir untersuchen dann den berechneten Stil für die animierte Eigenschaft, um zu sehen, ob sie sich unterscheidet, wenn die Animation vom ursprünglichen Frame beginnt, verglichen mit dem Zeitpunkt, an dem sie vom letzten Frame aus beginnt.

Der Grund dafür ist, dass die animierbaren Eigenschaften für Übergänge und Keyframe-Animationen identisch sind und der Browser nur Keyframe-Werte anwendet, wenn die Eigenschaft Animation unterstützt.

Caveats (lesen Sie vor der Verwendung, einige dieser böse sind!)

Es gibt mehrere Inkonsistenzen in Browsern wie Animationen umgehen.Ein paar davon habe ich so zukunftssicher wie möglich umgesetzt; Einige von ihnen sind jedoch schwer zu handhaben.

Am bemerkenswertesten sind Firefox-Tweens Positionswerte (z. B. left) auf statischen Elementen, während andere (z. B. Webkit und Opera) dies nicht tun. Es ist nicht wirklich Verschieben Sie das Element, aber der Wert dieser Eigenschaft wird aktualisiert. Daher erhalten Sie unterschiedliche Ergebnisse zwischen Browsern, wenn Sie versuchen, einen Positionswert zu animieren, ohne ein nicht statisch positioniertes Element zu übergeben.

Die aktuellsten Versionen der wichtigsten Browser, die CSS-Übergänge unterstützen, unterstützen auch CSS-Keyframes, obwohl einige ältere Versionen die ersteren, aber nicht die letzteren unterstützen. (Z. B. Opera 11.)

Schließlich, wenn ich dies eleganter tun würde, würde ich prefixfree verwenden, um das richtige Präfix zu bestimmen, um direkt zu verwenden; zur Zeit teste ich gegen ein Array von Präfixen, beginnend mit der Version ohne Präfix.

+1

+1 Sehr cool! Es gibt "oben rechts unten rechts" falsch, weil das Test-Div nicht absolut positioniert ist. Ich bin mir nicht sicher, wie ich damit umgehen soll, vielleicht können Sie ein Element übergeben, um das Test-Div zu überschreiben? – Duopixel

+0

Guter Punkt! Das Hinzufügen eines optionalen Elementparameters scheint eine gute Idee zu sein. Ich bin sogar soweit gekommen, die Geige zu aktualisieren, als meine Breitbandverbindung totging. Ich werde die Erklärung aktualisieren, wenn ich wieder online bin! :) –

+1

Cool! Ein weiterer guter Test wäre die Animation von CSS-Transformationen auf Inline-Elementen, die fehlschlagen sollen. – Duopixel