Zufallszahlen in CSS

Avatar of Robin Rendle
Robin Rendle on

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

Ich bin neulich auf ein interessantes Problem gestoßen. Ich wollte ein Element mit einer zufälligen animation-duration animieren. Das war der nicht-randomisierte Ausgangspunkt

Siehe den Pen Zufallszahlen CSS #1 von Robin Rendle (@robinrendle) auf CodePen.

Das ist das CSS, das ich geschrieben habe, um die Animation zu erstellen

@keyframes flicker {
  0% {
    opacity: 1;
  }
  100% {
    opacity: 0;
  }
}

#red {
  animation: flicker 2s ease alternate infinite;
}

Bisher gut. Aber da passiert keine Randomisierung, das sind feste 2 Sekunden.

Ich wollte, dass die Animationszeit von 2 Sekunden zufällig ist. Ich wollte im Wesentlichen schreiben

.element {
  animation: flicker $randomNumber alternate infinite;
}

Wobei $randomNumber programmatisch randomisiert wird.

CSS-Präprozessoren wie Sass bieten zwar eine random()-Funktion.

$randomNumber: random(5);

.thing {
  animation-duration: $randomNumber + s;
}

Das mag für Sie perfekt sein, für mich war es nicht ganz perfekt. Zufallszahlen, die während der Vorverarbeitung generiert werden, haben einen großen Nachteil

Mit anderen Worten, sobald das CSS verarbeitet ist, ist die Randomisierung beendet. Diese Zahl ist für immer auf diesen Wert festgelegt (d. h. bis der Präprozessor erneut ausgeführt wird).

Es ist nicht wie eine Zufallszahl in JavaScript (z. B. Math.random()), bei der diese Zufallszahl generiert wird, wenn das JavaScript ausgeführt wird.

Nachdem ich also so laut geseufzt habe, wie ich nur konnte, erkannte ich, dass dies tatsächlich die perfekte Gelegenheit wäre, native CSS-Variablen (Custom Properties) zu verwenden! Allein können sie keine Zufallszahlen einfacher generieren, aber wie wir sehen werden, können sie uns trotzdem helfen.

Wenn Sie damit nicht vertraut sind, dann keine Sorge. Im Wesentlichen sind es native Variablen, die direkt in die CSS-Sprache integriert sind, aber sie unterscheiden sich von den Variablen, die Sie vielleicht von einem Präprozessor wie Sass oder Less kennen. Chris hat vor einiger Zeit viele der Vorteile aufgelistet

  • Sie können sie ohne die Notwendigkeit eines Präprozessors verwenden.
  • Sie vererben sich. Sie können eine Variable innerhalb jedes Selektors festlegen, um ihren aktuellen Wert festzulegen oder zu überschreiben.
  • Wenn sich ihre Werte ändern (z. B. durch eine Media Query oder einen anderen Zustand), malt der Browser nach Bedarf neu.
  • Sie können sie in JavaScript abrufen und manipulieren.

Dieser letzte Punkt ist für uns wichtig. Wir werden die Zufallszahl in JavaScript generieren und sie dann über Custom Properties nach CSS übertragen.

Der erste Schritt ist, die benötigte CSS-Custom-Property mit einem Standardwert zu erstellen (nützlich, falls das gleich geschriebene JavaScript aus irgendeinem Grund fehlschlägt)

/* set the default transition time */
:root {
  --animation-time: 2s; 
}

Jetzt können wir diese Variable in unserem CSS so verwenden

#red {
  animation: flicker var(--animation-time) ease alternate infinite;
}

Unspektakulär sind wir genau dort, wo wir angefangen haben. Aber obwohl diese Demo jetzt genau wie unsere zuvor animierte SVG aussieht, verwendet diese stattdessen CSS-Variablen. Sie können testen, ob alles funktioniert, indem Sie einfach die Variable im CSS ändern und sehen, wie sich die Animation aktualisiert.

Jetzt sind wir bereit, diese Custom-Property über JavaScript abzurufen und zu manipulieren.

var time = Math.random();

Von hier aus können wir den roten Kreis in der SVG finden und die CSS-Variable --animation-time über die setProperty-Methode ändern

var red = document.querySelector('#red');
red.style.setProperty('--animation-time', time +'s');

Und hier ist sie! Eine zufällig generierte Zahl in CSS, die auf eine SVG-Animation angewendet wird

Siehe den Pen Zufallszahlen CSS #3 von Robin Rendle (@robinrendle) auf CodePen.

Dies ist ein Schritt nach vorne, da die Zufallszahl generiert wird, wenn das JavaScript ausgeführt wird, sodass sie jedes Mal anders ist. Das ist ziemlich nah dran an dem, was wir wollten, aber machen wir es noch ein wenig schwieriger: Lassen Sie uns die animation-duration periodisch randomisieren, während sie läuft.

Glücklicherweise haben wir jetzt JavaScript zur Verfügung, sodass wir diese Custom-Property jederzeit aktualisieren können. Hier ist ein Beispiel, bei dem wir die animation-duration jede Sekunde aktualisieren

var red = document.querySelector('#red');

function setProperty(duration) {
  red.style.setProperty('--animation-time', duration +'s');
}

function changeAnimationTime() {
  var animationDuration = Math.random();
  setProperty(animationDuration);
}

setInterval(changeAnimationTime, 1000);

Das ist genau das, was ich gesucht habe

Siehe den Pen Zufallszahlen CSS #4 von Robin Rendle (@robinrendle) auf CodePen.

Es ist nützlich zu bedenken, dass die Unterstützung für CSS-Variablen (Custom Properties) immer noch etwas lückenhaft ist, seien Sie also vorsichtig. Obwohl wir das, was wir tun könnten, schrittweise verbessern könnten, wie folgt

#red {
  animation: flicker .5s ease alternate infinite;
  animation: flicker var(--animation-time) ease alternate infinite;
}

Wenn CSS-Variablen nicht unterstützt werden, erhalten wir immer noch eine Art von Animation, auch wenn sie nicht genau das ist, was wir wollen.


Es ist erwähnenswert, dass CSS-Variablen nicht die einzige Möglichkeit sind, die Animationsdauer zu randomisieren. Wir könnten über JavaScript auf das DOM-Element zugreifen und den zufälligen Wert direkt in den style einfügen

var red = document.querySelector('#red');
red.style.animationDuration = Math.floor(Math.random() * 5 + 1) + "s";

Wir könnten sogar warten, bis die Animation beendet ist, bevor wir eine neue Dauer festlegen, wenn wir wollen

var red = document.querySelector('#red');

function setRandomAnimationDuration() {
  red.style.animationDuration = Math.floor(Math.random() * 10 + 1) + "s";
}

red.addEventListener("animationiteration", setRandomAnimationDuration);

Nur um eine weitere Möglichkeit einzubringen, könnten Sie dies auch mit EQCSS tun.

@element '#animation' {
  .element {
    animation-duration: eval('rand')s;
  }
}
var rand = Math.random();
EQCSS.apply();

Hier ist die minimale Demo und eine tatsächliche Demo.


Wünschen Sie sich, dass Randomisierung direkt in CSS verfügbar wäre? Ich bin mir nicht sicher, ob es darüber Gespräche gibt. Selbst wenn es welche gäbe, müssten wir wahrscheinlich noch lange warten, bis wir sie tatsächlich nutzen könnten. In diesem Sinne schrieb Philip Walton kürzlich, wie schwierig es wäre, einen echten Polyfill für Zufallszahlen in CSS zu schreiben. Viel einfacher, das in JavaScript zu handhaben!