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
Zufall in Sass ist wie zufällige Auswahl des Namens einer Hauptfigur in einer Geschichte. Es ist nur zufällig, wenn es geschrieben wird. Es ändert sich nicht.
— jake albaugh (@jake_albaugh) 29. Dezember 2016
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!
Was ich mir in CSS wirklich wünsche, sind Funktionen (nicht nur Zufallszahlen, die eingeschränkte Anwendungsfälle haben) und eine Möglichkeit, sie zu definieren. Mal sehen, was Houdini zu bieten hat!
Animationsereignisse kommen mir sofort in den Sinn, nachdem ich die
setTimeout-Methode gesehen habe. Aus irgendeinem Grund führt das Abhören vonanimationiterationjedoch zu unregelmäßigem Flackern sowohl in Firefox als auch in Chrome. https://codepen.io/jtojnar/pen/bgpNMKIch habe genau dasselbe festgestellt, als ich damit herumgespielt habe. Die Lösung entzieht sich mir.
Ich bin überrascht, dass Sie
--animation-timein #red und nicht in :root geändert haben. Möglicherweise möchten andere Verwendungen von--animation-timedieselbe Randomisierung haben. Nur #red sieht die Randomisierung, indem sie dort geändert wird.Wenn Sie beabsichtigen, dass nur #red sie sieht, dann wäre die Definition dort ausreichend, ohne sie in :root zu definieren, oder übersehe ich etwas?
Das zeigt diesen interessanten Aspekt von Custom Properties: den Geltungsbereich!
Hallo,
Ich hatte gerade einen anderen Ansatz im Sinn. Nicht ganz zufällig, aber trotzdem eine gültige Idee.
Man könnte auch sagen, 10 CSS-Klassen mit unterschiedlichen Dauern haben. Und fügen Sie einfach eine zufällige dieser mit JS hinzu oder servieren Sie eine zufällige mit PHP zu Ihrem HTML.
Es ist kein perfektes Zufallszahl in CSS, das stimmt, aber es hätte trotzdem denselben Effekt und würde weniger neue Funktionen nutzen.
Ein weiterer Ansatz könnte die Verwendung mehrerer Elemente (mit ihren Animationen) und das Zikadenprinzip sein
Siehe den Pen Zufällige Animation nur CSS von Kseso (@Kseso) auf CodePen.
Wie bekomme ich die Randomisierung in iOS 10 Safari zum Laufen, da caniuse sagt, dass es funktioniert? Ich bekomme jedes Intervall dieselbe Dauer.
Ich lese gerade Lea Verou’s Buch „CSS Secrets“, wo sie zufällige Hintergrundbreiten mit dem „Zikadenprinzip“ erstellt https://www.sitepoint.com/the-cicada-principle-and-why-it-matters-to-web-designers/, was hier zutreffen könnte.