Die CPU-Auslastung der CSS-Keyframe-Animation ist hoch. Sollte dies so sein?

78

Ich verwende die folgende Keyframe-Animation für mehrere Elemente:

@keyframes redPulse {
    from { background-color: #bc330d; box-shadow: 0 0 9px #333; }
    50% { background-color: #e33100; box-shadow: 0 0 18px #e33100; }
    to { background-color: #bc330d; box-shadow: 0 0 9px #333; }
}
@-webkit-keyframes redPulse {
    from { background-color: #bc330d; box-shadow: 0 0 9px #333; }
    50% { background-color: #e33100; box-shadow: 0 0 18px #e33100; }
    to { background-color: #bc330d; box-shadow: 0 0 9px #333; }
}
.event_indicator {
    display: inline-block;
    background-color: red;
    width: 5px;
    margin-right: 5px;

    -webkit-animation-name: redPulse;
    -webkit-animation-duration: 1s;
    -webkit-animation-iteration-count: infinite;

    animation-name: redPulse;
    animation-duration: 1s;
    animation-iteration-count: infinite;
}

Auf meinem Computer habe ich sowohl in Chrome als auch in Firefox eine CPU-Auslastung von ca. 40%. Ist es der aktuelle Stand der Animationen (nett, aber momentan nicht verwendbar) oder fehlt mir eine magische Eigenschaft?

Sie können das folgende Beispiel mit derselben Animation überprüfen: http://jsfiddle.net/Nrp6Q/

Ilya Tsuryev
quelle
1
Neben der hohen CPU scheint es in meinem Fall auch mit einem immer größeren Speicherbedarf verbunden zu sein, der auf dem Chrome Task Manager basiert.
Kevin Bullaughey
@ KevinBullaughey, anscheinend ist jedes Objekt mit Kosten verbunden: Sie belegen Speicher im System-RAM und / oder auf der GPU, siehe Erklärung , und die Animation selbst ist eine relativ teure Operation!
Farside
2
animiere keinen Kastenschatten. Verschieben Sie stattdessen die Box-Shadow-Eigenschaft in ein Pseudoelement und animieren Sie die Deckkraft und transformieren Sie die Eigenschaften
Denis
@Denis move box-shadow property to pseudoelement and animate it's opacity and transform propertiesIch weiß, dass die Frage des OP ziemlich alt ist, aber könnten Sie ein Beispiel oder eine Referenz angeben ?
Tonix

Antworten:

89

Ja, dies ist normal, da die Seite mehrere Endlosschleifenanimationen enthält. Die CPU arbeitet daher kontinuierlich, während diese Elemente gerendert werden. Es gibt eine "magische" Eigenschaft, die die CPU-Auslastung erheblich reduziert, und zwar:

transform: translateZ(0);

Dadurch werden die Elemente zu eigenen Ebenen zusammengefasst (indem der Browser zu der Annahme verleitet wird, dass 3D-Transformationen durchgeführt werden), und der Browser sollte in den meisten Fällen die GPU-Beschleunigung nutzen, um die CPU zu entlasten. Für mich hat sich das um etwa 20% (fast die Hälfte) verringert.

Weitere Informationen zu dieser Technik finden Sie unter: http://ariya.blogspot.com/2011/07/fluid-animation-with-accelerated.html

Je mehr Keyframes Sie in der Animation haben, desto anstrengender wird es auch. Probieren Sie einfach die Animation mit ausgeschnittenem mittleren Keyframe aus und Sie werden einen weiteren erheblichen Rückgang (~ 10-12%) der CPU-Auslastung feststellen.

Schließlich sind nicht alle Eigenschaften gleich - Box-Shadow ist für den Browser viel schwieriger zu animieren als beispielsweise Hintergrundfarben. Wenn Sie alle Keyframes intakt lassen, aber die Box-Shadow-Eigenschaft mit dem Trick translateZ (0) löschen, lag meine CPU-Auslastung nur bei 10-11%.

So sehr es mich auch schmerzt, dies zu sagen, für Animationen mit Endlosschleifen wird eine animierte GIF-Datei im aktuellen Status der Browseranimation viel, viel besser als CSS3 funktionieren, insbesondere wenn Sie vorhaben, dass viele davon auf der Website gerendert bleiben Seite für einige Zeit.

Update 2017:

Für diejenigen, die immer noch den Weg zu dieser Frage und Antwort finden, translate3d(0, 0, 0)bietet dies den gleichen Vorteil wie translateZ(0), Sie setzen nur translateX()und translateY()zur gleichen Zeit. Bitte ignorieren Sie den Kommentar von @Farside, wie er ihn translate3d(X, Y, Z)in seiner Demo verwendet, aber nicht mit ihm translate(X, Y), was zeigen würde, dass die Verwendung dieser Technik immer noch einen signifikanten Unterschied macht.

Nach dieser Frage haben einige Leute eine bessere Leistung in allen Browsern gefunden, insbesondere in Chrome transform: rotateZ(360deg).

skyline3000
quelle
3
Nein, es macht keinen Unterschied mehr , versucht in Firefox 45.0.2 und versucht in Chrome 50.0.2661. Ich denke, es wird so viel GPU wie möglich angewendet, auch ohne gefälschte Transformationen translateZ(0). Es scheint mir, dass CSS-Animationen derzeit eine schlechte Idee sind, da sie bei einfachen Animationen mit trivialem Quadrat die CPU stark aufheizen.
Farside
1
Warum abstimmen, wenn Ihre Ergebnisse mit dem übereinstimmen, was ich oben geschrieben habe? In diesem Beispiel läuft eine Endlosschleife - meine CPU-Auslastung liegt zwischen 10 und 14%. Sie haben translate3d verwendet, was der Verwendung von translatez (0) entspricht. Wenn Sie entfernen, steigt die CPU-Auslastung. Es macht sicherlich noch einen Unterschied.
skyline3000
4
@Farside Bitte überlegen Sie, Ihren Kommentar zu bearbeiten oder zu löschen, da er definitiv falsch ist und Fehlinformationen enthält. Ihre Demo vergleicht keine Animationen mit und ohne translateZ(0), sondern zeigt nur translate3d(x, y, z). Wenn Sie das mit nur vergleichen translate(x, y), würden Sie den signifikanten Unterschied sehen, den diese Methode immer noch macht.
skyline3000
1
Vielen Dank! Reduziert die CPU-Auslastung von 170% (!) Auf 13%. Beeindruckend.
Zack Katz
1
@ skyline3000 Die translateZ-Methode scheint die Leistung unter macOS nicht zu verbessern. Hier ist mein Beispiel stackoverflow.com/questions/47296808/…
Winston
15

Eine der möglichen Möglichkeiten, die CPU-Belastung zu reduzieren, ist die Verwendung einer sogenannten CPU null transform hack, die oft als eine Art Silberkugel bezeichnet wird . In vielen Fällen wird die Renderleistung in WebKit- und Blink-Browsern wie Chrome, Opera und Safari drastisch verbessert.

Verwendung des "Null Transform Hack" (ein Hardware-Compositing-Modus)

Der Null-Transformations-Hack macht im Grunde zwei Dinge:

  1. Es schaltet den Hardware-Compositing-Modus ein (vorausgesetzt, er wird für die Plattform unterstützt).
  2. Es wird eine neue Schicht mit eigener Trägeroberfläche erstellt

Um einen Browser zu "erzwingen", fügen Sie dem Element einfach eine dieser CSS-Eigenschaften hinzu:

transform: translateZ(0);

/* or its friend: */
transform: translate3d(0, 0, 0);

Wenn Sie mit 3D-Transformationen arbeiten, sollten Sie auch über diese Eigenschaften verfügen , um die Leistung zu verbessern :

backface-visibility: hidden;
perspective: 1000;

Vorbehalte des "Null Transform Hack"

Das Aktivieren einer Hardwarebeschleunigung in CSS3 für viele Objekte kann die Leistung beeinträchtigen! Anscheinend erzeugt jede Null-3D-Transformation eine neue Ebene. Die Erstellung von Force-Hacking-Ebenen ist jedoch möglicherweise nicht immer die Lösung für bestimmte Leistungsengpässe auf einer Seite. Layer-Erstellungstechniken können die Seitengeschwindigkeit erhöhen, sind jedoch mit Kosten verbunden: Sie belegen Speicherplatz im System-RAM und auf der GPU. Selbst wenn die GPU gute Arbeit leistet, kann die Übertragung vieler Objekte ein Problem darstellen, sodass sich die Verwendung der GPU-Beschleunigung möglicherweise nicht lohnt. Das Zitat von W3C :

Das Einrichten des Elements in einer neuen Ebene ist jedoch eine relativ teure Operation, die den Start einer Transformationsanimation um einen merklichen Sekundenbruchteil verzögern kann.

Das Verschieben einiger großer Objekte hat eine höhere Leistung als das Verschieben vieler kleiner Objekte bei Verwendung der 3D-Beschleunigung. So müssen sie mit Bedacht verwendet werden , und Sie müssen sicherstellen , dass die Hardware-Beschleunigung der Operation wirklich die Leistung Ihrer Seite helfen wird, und dass eine Performance - Engpass nicht durch eine andere Operation auf Ihrer Seite verursacht wird.

Darüber hinaus wurde eine GPU speziell für die Durchführung komplexer mathematischer / geometrischer Berechnungen entwickelt, und das Auslagern von Vorgängen auf die GPU kann zu einem massiven Stromverbrauch führen . Wenn Hardware aktiviert wird, wird natürlich auch der Akku des Zielgeräts aktiviert.

Der moderne Weg: das will-changeAnwesen

Der Fortschritt steht nicht an einer Stelle ... W3C hat die will-changeCSS-Eigenschaft eingeführt. Um es kurz zu machen: Mit der will-changeEigenschaft können Sie den Browser im Voraus darüber informieren, welche Art von Änderungen Sie wahrscheinlich an einem Element vornehmen, damit er die entsprechenden Optimierungen vornehmen kann, bevor sie benötigt werden.

Folgendes sagen sie im Entwurf :

Mit will-changeder in dieser Spezifikation definierten Eigenschaft kann ein Autor im Voraus festlegen, welche Eigenschaften sich in Zukunft voraussichtlich ändern werden, sodass die UA einige Zeit vor ihrer Verwendung die entsprechenden Optimierungen vornehmen kann. Auf diese Weise wird die Seite bei der eigentlichen Änderung schnell aktualisiert.

Wenn Sie will-changedem Browser einen Hinweis auf eine bevorstehende Umwandlung geben, können Sie diese Regel einfach zu dem Element hinzufügen, dessen Umwandlung Sie erwarten:

will-change: transform;

Bei der Entwicklung für Mobilgeräte müssen Entwickler beim Schreiben mobiler Webanwendungen die zahlreichen Geräteeinschränkungen berücksichtigen. Browser werden schlauer, und manchmal ist es besser, die Entscheidung der Plattform selbst zu überlassen, anstatt die Beschleunigung zu überlappen und das Verhalten auf hackige Weise zu erzwingen.

Farside
quelle
Auf der MDN-Seite heißt es: "Wendet keine Willensänderung auf zu viele Elemente an." und "Sparsam verwenden." Unter der Haube setzen aktuelle Browser-Implementierungen dieser Eigenschaft wahrscheinlich immer noch nur die Elemente zusammen. Diese Funktion ist nicht nur nicht Standard (es ist immer noch ein Arbeitsentwurf), sondern auch eindeutig nicht der "Silberkugel" -Ansatz, den Sie sich vorstellen. Darüber hinaus erklärt Ihre Antwort weder die CPU-Auslastung des OP noch zeigt Sie Vergleiche der CPU-Auslastung.
skyline3000
2
@ skyline3000, ich schrieb Vor-, Nachteile und Vorbehalte. Lesen Sie genauer durch, will-change- ist nicht meine Empfehlung, aber es ist eine elegantere und modernere Art, "dem Browser einen Hinweis auf die bevorstehende Transformation zu geben" , anstatt ihn zu erzwingen. "als eine Art Silberkugel gepriesen" - gehört zu dem sogenannten null transform hackund nicht zum will-changeEigentum, wie Sie sagen. Ich bin in Ordnung mit Ihrer Abwahl, ich verstehe, dass Sie Angst vor der Konkurrenz haben könnten;)
Farside
4

Ich hatte einen ähnlichen Fall von hoher CPU-Auslastung, als ich einige Elemente mit CSS3 animierte. Ich habe die "linke" Eigenschaft von ~ 7 Elementen mit einigen Deckkraft- und Schatteneigenschaften animiert, die auf meiner gesamten Seite verwendet wurden. Ich habe mich für jQuery.animate entschieden, was die Leistung leider überhaupt nicht verbessert hat. Meine CPU (i7) war beim Anzeigen der Seite immer noch bei ~ 9-15%, einige Tricks (translateZ usw.) haben die Leistung auch nicht wirklich verbessert - während mein Layout durcheinander gebracht wurde (einige absolut positionierte Elemente waren beteiligt, autsch !).

Dann bin ich auf diese wundervolle Erweiterung gestoßen: http://playground.benbarnett.net/jquery-animate-enhanced/

Ich habe einfach auf die .js-Datei verwiesen, bei den jQuery-Übergängen keine einzige Änderung vorgenommen, und meine CPU-Auslastung beträgt jetzt 1-2% auf derselben Seite.

Meine Empfehlung: Wenn Sie mit CSS3-Übergängen auf CPU-Probleme stoßen, wechseln Sie zu jQuery + dem animierten Plugin.

konrad_pe
quelle
1
In den meisten Fällen enthalten viele Projekte keine Abfrage als Abhängigkeit, sodass das Importieren eines zusätzlichen Bundles möglicherweise nicht akzeptabel ist.
Dimitris Filippou
3

Sie können dies auch für eines der folgenden Klassenelemente verwenden, bei denen Sie die GPU anstelle der CPU verwenden möchten

.no-cpu {
    transform: translateZ(0);
    -webkit-transform: translateZ(0);
    -ms-transform: translateZ(0);
}

<element class="event_indicator no-cpu">animation...</element >
user1467439
quelle
1
Sie haben die 'Willensänderungen' vergessen und sollten sie auch in 'force-gpu' umbenennen, da 'no-cpu' sehr ungenau und sehr irreführend ist.
1

Für einen bestimmten Fall von "pulsierender" Hintergrundanimation, der hier berichtet wird, habe ich eine CSS + JS-Lösung entwickelt.

In meinem Fall befand sich die Hintergrundanimation eher in der Eigenschaft "Hintergrundposition" als in der Hintergrundfarbe, aber das Prinzip ist dasselbe.

Angenommen, Sie haben einen Block mit einem bestimmten Hintergrund:

<div class="nice-block">...</div>

Lassen Sie es uns stylen: (scss)

.nice-block {
  background-color: red;
  //or it can be: background: linear-gradient(45deg, #red, #white, #red);
  //and:          background-size: 600% 600%;

  //the transform and will-change properties
  //are here to only enable GPU
  transform: translateZ(0);
  -webkit-transform: translateZ(0);
  -ms-transform: translateZ(0);
  will-change: transform;

  transition: background-color 5s ease;
  //if you want to add a pulsing effect 
  //to a gradient, see the following two lines:
  // background-position: 0% 50%!important;
  // transition: background-position 5s ease;

  &.animated {
    background-color: white;
    //and in case of gradient animation:
    // background-position: 100% 50%!important;
  }
}

Jetzt ist es an der Zeit, den Effekt zu erzielen, indem Sie dem Block eine Klasse 'animiert' mit etwas JavaScript hinzufügen:

var bgAnimateTimer;
function animateBg () {
  clearTimeout(bgAnimateTimer);
  bgAnimateTimer = setTimeout(function () {
    clearTimeout(bgAnimateTimer);
    bgAnimateTimer = setTimeout(function () {

      document.querySelector('.nice-block').classList.toggle('animated');

      //jQuery alternative is:
      // $('.nice-block').toggleClass('animated');

      animateBg ();
    }, 5000); //5 seconds for the animation effect
  }, 2500); //2.5 seconds between each animation
}

animateBg ();

Dies verbesserte die Leistung in meinem Fall um das ~ 15-fache.

(i) Beachten Sie, dass Sie die Sekunden für Übergang und Zeitüberschreitung sowohl in CSS als auch in JS korrekt berechnen müssen, wenn Sie andere Werte als 5 Sekunden wünschen.

Oleg K.
quelle