Joschi: Meinung zu Animation via CSS-Klassen?

Hallo,

Hab ein bisschen in dem Forum hier gestöbert und scheint so dass die Leute hier wissen was sie tun und wovon sie reden. Ich brauche eigentlich weniger Hilfe als eine fachkundige Meinung.

Ich schreibe gerade an einem Javascript Minigame, in dem eine Figur mithilfe von CSS-Klassen navigiert, also in die Richtung

#Objekt {
	transition: all 2s;
}
/* Objekt hat folgende Klasse */
.Anfangsposition {
	top: 10px;
	left: 10px;
}
/* Objekt hat folgende Klasse nicht */
.Endposition {
	top: 10px;
	left: 500px;
}

Dann tausche ich die Klassen aus, und das Objekt "fährt" auf der x-Achse nach rechts:

Element.removeAttribute("class");
/* Element hat nur eine Klasse,
daher würde mir bei "classList.remove"
ein "totes" Class-Attribut übrigbleiben */

Element.classList.add("Endposition");

Kommt mir ein wenig hacky vor - oder bin das nur ich? Würdet ihr das ähnlich lösen?

LG Joschi

  1. Herzlich willkommen!

    Ich brauche eigentlich weniger Hilfe als eine fachkundige Meinung.

    Ich schreibe gerade an einem Javascript Minigame, in dem eine Figur mithilfe von CSS-Klassen navigiert, also in die Richtung

    /* Objekt hat folgende Klasse */
    .Anfangsposition {
    	top: 10px;
    	left: 10px;
    }
    /* Objekt hat folgende Klasse nicht */
    .Endposition {
    	top: 10px;
    	left: 500px;
    }
    

    Das funktioniert ja, ist daher aus meiner Sicht ok. Andererseits sind das imho eher Daten, die ich irgendwo im JS definieren würde:

    var	step = {
    		  right: {
    			  x: 50,
    			  y: 0
    				  },
           down: {
    			  x: 0,
    			  y: 50
    			  };	
    

    Dann tausche ich die Klassen aus, und das Objekt "fährt" auf der x-Achse nach rechts:

    Diese Daten könntest Du dann in eine transform einsetzen:

    Entweder per CSS oder mit der WAAPI (Web Animations API)

    Siehe Beispiel Ball

    Anstelle der festen Zahlenwerte im Beispiel könntest du deine Werte einsetzen:

    var move = [
      { 
        transform: 'translate(0, 0)',
        background: 'green'    
      },
      { 
        transform: 'translate(' + step.right.x + 'px', + step.right.y + 'px')',
        background: 'lime'    
      },
      {
       transform: 'translate(0px, 0px)',
       background: 'lime'   
      }
    ];
    
    Element.removeAttribute("class");
    /* Element hat nur eine Klasse,
    daher würde mir bei "classList.remove"
    ein "totes" Class-Attribut übrigbleiben */
    
    Element.classList.add("Endposition");
    

    Das Klassen nicht immer verwendet werden, ist doch ok, ein leeres class="" im DOM ist imho legitim; ich würde aber doch die ganze transform in die Klasse schreiben und nicht nur die Positionen.

    Stellst du Dein Projekt mal näher vor?

    Herzliche Grüße

    Matthias Scharwies

    --
    25 Jahre SELFHTML → SELF-Treffen 05.-07. Juni 2020 in Mannheim
  2. Hallo Joschi,

    ich würde mal prüfen, wieviel Rechenleistung beim Ändern der Klassen verbraucht wird. In diesem Beispiel werden die Positionen direkt geändert.

    Gruß
    Jürgen

    1. Hallo JürgenB,

      ich würde mal prüfen, wieviel Rechenleistung beim Ändern der Klassen verbraucht wird. In diesem Beispiel werden die Positionen direkt geändert.

      Das ist ein wenig abhänging vom Browser, aber modernere Browser rendern CSS GPU-beschleunigt, so dass es tatsächlich effizienter ist Animationen über CSS zu machen.

      Das ist auch ein wichtiger Grund, warum das immer empfohlen wird.

      Freundliche Grüße,
      Christian Kruse

      1. Hallo Christian,

        ist denn xxx.style.top = 42% kein css?

        Mein Verdacht ist, dass das Ändern von Klassen teurer ist, als das Ändern von Style-Werten. Aber das müsste man bzw. Joschi mal testen.

        Gruß
        Jürgen

        1. Hallo JürgenB,

          ist denn xxx.style.top = 42% kein css?

          Doch, klar.

          Mein Verdacht ist, dass das Ändern von Klassen teurer ist, als das Ändern von Style-Werten.

          Das halte ich für unwahrscheinlich unwahrscheinlich. Aber selbst wenn das so wäre: eine solche Animation ist trotz allem noch sinnvoller, da der Browser die Kontrolle behält. Er macht die Berechnungen mit der CSS-Engine, kann also selbstständig entscheiden, wie er sie wo ausführt (GPU vs CPU), er kann entscheiden Frames zu skippen und/oder direkt zum nächsten Keyframe zu springen oder sogar die Animation abschalten, wenn der Tab bzw der Bereich auf der Seite nicht sichtbar ist.

          Dass das besser ist als der alte Weg, wo man Pixel für Pixel das Element verschoben hat, ist allerdings unbestritten.

          Aber das müsste man bzw. Joschi mal testen.

          Nee, hat schon jemand getan 😉 Paul-Peter Koch von Quirksmode.org: Benchmark - style vs. className. Wenn man dort auf „Create new test table“ klickt und beide Tests einmal ausführen lässt, dann kann man auch sehen, wie sich das in dem Browser, den man gerade nutzt, auswirkt. Und bei mir kommt da raus: className ist ca. 50% schneller.

          Freundliche Grüße,
          Christian Kruse

          1. Hallo Christian,

            ich habe den von Dir genannten Test mal nachprogrammiert und finde nur geringe Laufzeitunterschiede. Merklich sind sie ohnehin nur bei tausenden von Zellen. Für die Animation eines einzelnen Elementes ist das irrelevant.

            Entscheidungskriterium sollte sein: Sofern sich die Animation mittels CSS Animation darstellen lässt (d.h. die gewünschte räumliche und zeitliche Abfolge von Positionen), sollte man das auch tun. Angesichts der Möglichkeiten, die Keyframes bieten, gibt es eine Menge Luft nach oben, bevor man an die Decke stößt. Ist die Bewegung dennoch zu komplex, kann man sie entweder per Script aus CSS Animationen zusammensetzen (was sicherlich tricky ist) oder komplett zu Fuß animieren. In dem Fall dann aber über das style-Attribut und passende Eigenschaften (z.B. transform).

            Ob man die CSS Animation mittels direkter Zuweisung eines style-Attributs oder durch Setzen einer Klasse auslöst, ist aber eine andere Frage. Eine Klasse bietet sich an, wenn es sich um eine Standard-Animation handelt. Sobald Dinge berechnet werden müssen (über die in CSS gegebenen Möglichkeiten hinaus), ist eher style angebracht. Werden Keyframes gebraucht, muss das ohnehin im Stylesheet angegeben werden. Durch Einsatz von Custom Properties (aka CSS Variablen) kann man CSS Regeln und Keyframes auch noch dynamisch modifizieren.

            p {
              --dauer: 1s;
              --topFrom: 10px;
              --topTo: 100px;
              position: absolute;
              animation-duration: var(--dauer);
              animation-name: moveTop;
            }
            
            @keyframes moveTop {
              from {  top: var(--topFrom);  }
              to {  top: var(--topTo); }
            }
            
            <p style="--topFrom: 100px; --topTo: 0px; --dauer: 10s">Ein Ring, sie zu knechten</p>
            

            Es gibt also kein starres richtig und falsch, sondern wie immer ist es ein "kommt drauf an was man braucht".

            Rolf

            --
            sumpsi - posui - clusi
            1. Hallo Rolf,

              ich habe den von Dir genannten Test mal nachprogrammiert und finde nur geringe Laufzeitunterschiede. Merklich sind sie ohnehin nur bei tausenden von Zellen. Für die Animation eines einzelnen Elementes ist das irrelevant.

              Natürlich. Die Frage, die Jürgen hier gestellt hat, ist aber nicht „ist der Unterschied relevant“ sondern „gibt es einen Unterschied?“ Diese Frage habe ich versucht zu beantworten. Darüber, ob es immer richtig ist, Animationen nur mit Klassen umzusetzen, habe ich doch gar nicht referiert.

              Es gibt also kein starres richtig und falsch, […]

              Ich kann beim besten Willen nicht nachvollziehen, wo du das hinein gelesen hast…

              Freundliche Grüße,
              Christian Kruse

          2. Hallo Christian,

            Nee, hat schon jemand getan 😉 Paul-Peter Koch von Quirksmode.org: Benchmark - style vs. className. Wenn man dort auf „Create new test table“ klickt und beide Tests einmal ausführen lässt, dann kann man auch sehen, wie sich das in dem Browser, den man gerade nutzt, auswirkt. Und bei mir kommt da raus: className ist ca. 50% schneller.

            interesant. Das hätte ich jetzt nicht erwartet. Allerding werden in dem Test nur Farbe und Schriftgröße gesetzt. Wie das bei Positionen aussieht, und ob man einen vorgegeben Bewegungspfad über viele Klassen mit den Eckpunkten realisiert, oder über Setzen von top und left, ist wahrscheinlich ein anderer Test. Die „feine“ Bewegung sollte aber über transition laufen.

            Gruß
            Jürgen

        2. @@JürgenB

          ist denn xxx.style.top = 42% kein css?

          Aus Performanz-Gründen sollte man top nicht animieren, sondern möglichst nur transform und opacity.

          Bewegungen kann man performant mit Änderungen von transform: transition(…) realisieren.

          LLAP 🖖

          --
          „Man kann sich halt nicht sicher sein“, sagt der Mann auf der Straße, „dass in einer Gruppe Flüchtlinge nicht auch Arschlöcher sind.“
          „Stimmt wohl“, sagt das Känguru, „aber immerhin kann man sich sicher sein, dass in einer Gruppe Rassisten nur Arschlöcher sind.“

          —Marc-Uwe Kling
          1. Hallo Gunnar,

            Bewegungen kann man performant mit Änderungen von transform: transition(…) realisieren.

            meinst du transform: translate(…)?

            Gruß
            Jürgen

            1. @@JürgenB

              Bewegungen kann man performant mit Änderungen von transform: transition(…) realisieren.

              meinst du transform: translate(…)?

              Natürlich. Bin mit den Transen durcheinandergekommen.

              LLAP 🖖

              --
              „Man kann sich halt nicht sicher sein“, sagt der Mann auf der Straße, „dass in einer Gruppe Flüchtlinge nicht auch Arschlöcher sind.“
              „Stimmt wohl“, sagt das Känguru, „aber immerhin kann man sich sicher sein, dass in einer Gruppe Rassisten nur Arschlöcher sind.“

              —Marc-Uwe Kling
  3. @@Joschi

    Element.removeAttribute("class");
    /* Element hat nur eine Klasse,
    daher würde mir bei "classList.remove"
    ein "totes" Class-Attribut übrigbleiben */
    

    Ja, und? Zum einen wäre das nicht tragisch, zum anderen wird das ja sofort wiederbelebt:

    Element.classList.remove("Anfangsposition");
    Element.classList.add("Endposition");
    

    Wenn bei dem Element keine anderen Klassen im Spiel sind, kannst du die vorhandene auch einfach so überschreiben:

    Element.className = "Endposition";
    

    LLAP 🖖

    --
    „Man kann sich halt nicht sicher sein“, sagt der Mann auf der Straße, „dass in einer Gruppe Flüchtlinge nicht auch Arschlöcher sind.“
    „Stimmt wohl“, sagt das Känguru, „aber immerhin kann man sich sicher sein, dass in einer Gruppe Rassisten nur Arschlöcher sind.“

    —Marc-Uwe Kling
  4. Hallo Joschi,

    die Frage wäre, ob Du überhaupt eine Klasse für die Anfangsposition brauchst. Du kannst die Anfangsposition - je nach Aufgabe - auch direkt in der CSS Regel für #Objekt unterbringen. Dann musst Du nur noch die Klasse für die Endposition setzen oder wieder entfernen, um das Objekt zu animieren.

    Dass dabei ggf. ein Attribut class="" entsteht, braucht Dich nicht zu stören. Es darf Dir nur nicht einfallen, die Existenz des class Attributs als Indiz für "da liegt eine Klasse vor" zu verwenden. Bleibe bei classList und den Eigenschaften und Methoden dieses Objekts, und alles ist gut (außer im Internet Explorer, der ist da aus Altersgründen eher rudimentär unterwegs)

    Rolf

    --
    sumpsi - posui - clusi