React App: Flexbox mit gleicher Spaltenbreite durch flex-basis: 100-Prozent

Gleichmäßige Spaltenbreiten lassen sich mit display:flex beim Parent-Element und flex-basis: 100% beim child-Element einfach und intuitiv umsetzen. Auch dann noch, wenn sich die Anzahl der Spalten dynamisch ändert. Eine React-App zeigt die optische Wirkung.

Tuedo#004

 von  tuedodev

02
Mär 2021
 0

Gleichmäßige Spaltenbreiten lassen sich mit display:flex beim Parent-Element und flex-basis: 100% beim child-Element einfach und intuitiv umsetzen. Auch dann noch, wenn sich die Anzahl der Spalten dynamisch ändert. Eine React-App zeigt die optische Wirkung.

Github Repository des Codes

CodePen-Demo

Für gleichmäßig breite Spalten beim Design einer Website gibt es mehrere Möglichkeiten, mit Flexbox gibt es aber eine besonders einfache und intuitive1. Setzt man das Parent-Element auf display: flex und die Child-Elemente auf flex-basis: 100% werden die Spalten gleichmäßig breit dargestellt. Wenn eine Spalte dynamisch hinzugefügt oder entfernt wird, entfällt das aufwendige und fehleranfällige Berechnen der einzelnen Spalten mit Pixeln oder Prozentangaben.

Dabei ist man übrigens gar nicht auf gleichmäßig breite Spalten festgelegt (oder bei flex-direction: column auf Layoutzeilen), sondern kann bei den Child-Elementen auch Verhältnisangaben mühelos und eingängig festlegen (z. B. zwei Drittel – ein Drittel).

React-App mit Animationen

Mit einer kleinen React-App habe ich diesen Effekt optisch umgesetzt, sodass der Nutzer die Anzahl der Spalten und die flex-basis-Prozentangaben der Spaltenelemente frei festlegen kann. Die React-App wird durch Animationen aufgewertet und besteht aus den Komponenten App.js, Card.js, ColumnDisplay.js und DisplayInterval.js.

App.js umfasst die Hauptkomponente, die die vom Nutzer änderbare Anzahl der Childkomponenten als Cards per Mapping ausgibt.

<ul className="mb-4 card-container" style={{display: 'flex', flexDirection: 'row',}}>
    {
        cardArray.map((cardItem, index) => <Card {...cardItem} key={idArr.current[index]}/>)
    }
</ul>

Die Card-Komponente (die jeweils eine Spalte repräsentieren soll) umfasst die animierte Darstellung der Prozentangaben durch die Komponente DisplayInterval sowie das Handling der drei Buttons. Die Komponente ColumnDisplay zeigt die Anzahl der Cards mit Symbolen an.

Technisch aufwendiger als die bloße Darstellung der Spaltenanzahl mit Symbolen ist die Animation der hinzukommenden oder abgehenden Karten auf der rechten Bildschirmseite. Weil React beim Entfernen einer Karte die Darstellung des Karten-Containers sofort neu rendern würde, wird die Änderung des States durch eine setTimeout verzögert und mit die jeweiligen Cards mit CSS-Hilfsklassen entry und exit versehen, die die e@keyframes-Animationen steuern.

Browser-Animation mit requestAnimationFrame

Die Komponente DisplayInterval steuert die Anzeige der Prozentzahlen, die ein animiertes Hoch- und Runterzählen der Prozentangaben umsetzt. Ich nutze dabei die Browser-API-Funktion requestAnimationFrame, der eine Callback-Funktion (in diesem Fall animate) als Argument übergeben wird, die vor dem nächsten Repaint des Browsers aufgerufen wird. Diese Animation ist ressourcenschonender als die alten Javascript-Techniken setInterval und setTimeout, die auch dann noch arbeiten, wenn das Tab gerade nicht aktiv ist.

Der Animationsmethode animate muss man sich dabei anders annähern, als man das von den anderen Methoden gewohnt ist. Der springende Punkt ist, zu einer bestimmten Zeit (hierfür wird die vergangene Zeit seit Start der Methode in der Variablen deltaTime berechnet), den Zustand einer Animation zu berechnen. In meinem Fall musste also berechnet werden, welche Prozentzahl zu einer bestimmten Zeit dargestellt werden soll, wenn die Animation zum Beispiel 200 Millisekunden dauern soll.

const updatedNumber = Math.min(prevNumberRef.current + sign * Math.round(deltaTime / (duration / Math.abs(numberGap))), newNumber);
setCurrentNumber(updatedNumber);

Diese Berechnung übernimmt im oben dargestellten Beispiel die Variable updatedNumber.

Die Variablen und ihre Bedeutung:

  • updatedNumber: Die Berechnung der zu einer bestimmten Zeit darzustellenden Zahl
  • sign: Gibt das Vorzeichen plus eins oder minus eins an(Multiplikator 1 oder -1), die darüber entscheidet, ob die Zahl rauf oder runter geht
  • deltaTime: Die seit dem Start der Animation vergangene Zeit in Millisekunden
  • numberGap: Die Differenz zwischen altem und neuen Prozentwert
  • newNumber: Der Zielwert der Animation, die am Schluss der Animation darzustellende Zahl

Um Rundungsfehler zu vermeiden, wird mit der Math.min-Funktion innerhalb der Animation sichergestellt, dass die berechnete Zahl updatedNumber nie höher liegt als der Zielwert newNumber.

return () => cancelAnimationFrame(requestRef.current);

Diese Callback-Funktion innerhalb des useEffect-Hooks, der nach dem Rendern und nur beim Ändern der newNumber-Prop aufgerufen wird, räumt die Animation als Cleanup-Funktion auf und gibt den Speicherplatz für die Garbage Collection frei. Enjoy!

  1. Auf seinem Youtube-Kanal hat Kevin Powell diese Möglichkeit ausführlich dargestellt.

Dieser Beitrag wurde bisher nicht kommentiert.

Kommentar hinzufügen