CSS ermöglicht es Ihnen, dynamische Layouts und Oberflächen im Web zu erstellen, aber als Sprache ist es statisch: Sobald ein Wert festgelegt ist, kann er nicht mehr geändert werden. Die Idee von Zufälligkeit ist vom Tisch. Das Generieren von Zufallszahlen zur Laufzeit ist das Territorium von JavaScript, nicht wirklich von CSS. Oder doch? Wenn wir ein wenig Benutzerinteraktion einbeziehen, können wir tatsächlich einen gewissen Grad an Zufälligkeit in CSS erzeugen. Schauen wir es uns an!
Zufälligkeit aus anderen Sprachen
Es gibt Möglichkeiten, „dynamische Zufälligkeit“ mithilfe von CSS-Variablen zu erzielen, wie Robin Rendle in einem Artikel auf CSS-Tricks erklärt. Aber diese Lösungen sind nicht zu 100 % CSS, da sie JavaScript erfordern, um die CSS-Variable mit dem neuen Zufallswert zu aktualisieren.
Wir können Präprozessoren wie Sass oder Less verwenden, um Zufallswerte zu generieren, aber sobald der CSS-Code kompiliert und exportiert ist, sind die Werte fix und die Zufälligkeit geht verloren. Wie Jake Albaugh erklärt
random in sass is like randomly choosing the name of a main character in a story. it's only random when written. it doesn't change.
— jake albaugh (@jake_albaugh) December 29, 2016
Warum interessieren mich Zufallswerte in CSS?
Früher habe ich einfache CSS-only Apps entwickelt, wie z. B. ein Quizspiel, ein Simon-Spiel und einen Zaubertrick. Aber ich wollte etwas Komplizierteres machen. Ich werde eine Diskussion über die Gültigkeit, Nützlichkeit oder Praktikabilität der Erstellung solcher reinen CSS-Snippets für später aufheben.
Basierend auf der Prämisse, dass einige Brettspiele als endliche Automaten (FSM) dargestellt werden könnten, könnten sie mithilfe von HTML und CSS dargestellt werden. Also begann ich, ein Spiel „Leiterspiele“ (aka Chutes and Ladders) zu entwickeln. Es ist ein einfaches Spiel. Das Ziel ist es, einen Spielfiguren vom Anfang bis zum Ende des Spielfelds zu bewegen, wobei die Schlangen vermieden und die Leitern genutzt werden.
Das Projekt schien machbar, aber es gab etwas, das ich vermisste: **Würfel werfen**!
Das Würfeln (zusammen mit dem Münzwurf) ist universell als Zufälligkeit anerkannt. Man wirft die Würfel oder wirft die Münze und erhält jedes Mal einen unbekannten Wert.
Simulation eines zufälligen Würfelwurfs
Ich wollte Ebenen mit Beschriftungen übereinander legen und CSS-Animationen verwenden, um zu „rotieren“ und auszutauschen, welche Ebene oben lag. Etwas in dieser Art

Der Code zur Nachahmung dieser Zufälligkeit ist nicht übermäßig kompliziert und kann mit einer Animation und unterschiedlichen Animationsverzögerungen erreicht werden
/* The highest z-index is the numbers of sides in the dice */
@keyframes changeOrder {
from { z-index: 6; }
to { z-index: 1; }
}
/* All the labels overlap by using absolute positioning */
label {
animation: changeOrder 3s infinite linear;
background: #ddd;
cursor: pointer;
display: block;
left: 1rem;
padding: 1rem;
position: absolute;
top: 1rem;
user-select: none;
}
/* Negative delay so all parts of the animation are in motion */
label:nth-of-type(1) { animation-delay: -0.0s; }
label:nth-of-type(2) { animation-delay: -0.5s; }
label:nth-of-type(3) { animation-delay: -1.0s; }
label:nth-of-type(4) { animation-delay: -1.5s; }
label:nth-of-type(5) { animation-delay: -2.0s; }
label:nth-of-type(6) { animation-delay: -2.5s; }
Die Animation wurde verlangsamt, um die Interaktion zu erleichtern (aber immer noch schnell genug, um das unten erklärte Hindernis zu sehen). Die Pseudozufälligkeit ist ebenfalls klarer.
Siehe den Pen
Demo von pseudo-zufällig generierter Zahl mit CSS von Alvaro Montoro (@alvaromontoro)
auf CodePen.
Aber dann stieß ich auf ein Hindernis: Ich erhielt zwar Zufallszahlen, aber manchmal, selbst wenn ich auf meine „Würfel“ klickte, gab es *keinen* Wert zurück.
Ich habe versucht, die Zeiten in der Animation zu erhöhen, und das schien ein wenig zu helfen, aber ich hatte immer noch einige unerwartete Werte.
Da bat ich, wie die meisten Entwickler, wenn sie auf ein Hindernis stoßen, das sie nicht allein durch Online-Suche lösen können, andere Entwickler um Hilfe in Form einer StackOverflow-Frage.
Zu meinem Glück kam der stets findige Temani Afif mit einer Erklärung und einer Lösung.
Um es ein wenig zu vereinfachen: Das Problem war, dass der Browser das Klick-/Drückereignis nur dann auslöst, wenn das Element, das beim Drücken der Maustaste aktiv ist, dasselbe Element ist, das beim Loslassen der Maustaste aktiv ist.
Aufgrund der Rotationsanimation war das oberste Label beim Drücken der Maustaste nicht das oberste Label beim Loslassen der Maustaste, es sei denn, ich tat es schnell oder langsam genug, damit die Animation herumzirkulierte. Deshalb verbargen die erhöhten Animationszeiten diese Probleme.
Die Lösung bestand darin, eine Position „static“ anzuwenden, um den Stapelkontext zu durchbrechen, und ein Pseudoelement wie ::before oder ::after mit einem höheren z-index zu verwenden, um seinen Platz einzunehmen. So wäre das aktive Label beim Loslassen der Maustaste immer oben.
/* The active tag will be static and moved out of the window */
label:active {
margin-left: 200%;
position: static;
}
/* A pseudo-element of the label occupies all the space with a higher z-index */
label:active::before {
content: "";
position: absolute;
top: 0;
right: 0;
left: 0;
bottom: 0;
z-index: 10;
}
Hier ist der Code mit der Lösung bei schnellerer Animationszeit
Siehe den Pen
Demo von pseudo-zufällig generierter Zahl mit CSS von Alvaro Montoro (@alvaromontoro)
auf CodePen.
Nachdem diese Änderung vorgenommen worden war, blieb nur noch die Erstellung einer kleinen Benutzeroberfläche, um einen gefälschten Würfel zum Anklicken zu zeichnen, und das CSS-Spiel „Leiterspiele“ war fertig.
Diese Technik hat einige offensichtliche Nachteile
- Sie erfordert Benutzereingaben: ein Label muss angeklickt werden, um die „Zufallszahlengenerierung“ auszulösen.
- Sie skaliert nicht gut: Sie funktioniert gut mit kleinen Wertemengen, ist aber bei großen Bereichen mühsam.
- Sie ist nicht wirklich zufällig, sondern pseudo-zufällig: Ein Computer könnte leicht erkennen, welcher Wert zu jedem Zeitpunkt generiert werden würde.
Andererseits ist sie zu 100 % CSS (keine Präprozessoren oder andere externe Hilfsmittel erforderlich) und kann für einen menschlichen Benutzer zu 100 % zufällig aussehen.
Und wo wir gerade von Händen sprechen… Diese Methode kann nicht nur für Zufallszahlen, sondern für alles Zufällige verwendet werden. In diesem Fall haben wir sie verwendet, um die Computerwahl bei einem Stein-Schere-Papier-Spiel „zufällig“ auszuwählen.
Siehe den Pen
CSS Stein-Schere-Papier von Alvaro Montoro (@alvaromontoro)
auf CodePen.
Excellent article!!
First thing comes to my mind
.dice[data-random]::before {content:attr(data-random);}Would need another language (JS, PHP etc.) to fill in the
data-randomattribute in HTML, but it’s way more reliable, I think.Using another language is definitely more reliable and effective. This is more of a fun don’t-do-this-in-production approach.
Love this article! I’ve been driving into Javasript and randomization (of array elem) and have been questioning a pure-css solution. The journey has been amusing, building fun demos while banging my head off the keyboard. Thanks for sharing.
PS the rock paper … CTA event caused my mobile browser to reload and re-scroll to bottom just to see the result (it was a tie… sigh lol). Just an observation.
Thanks! That summarizes my experience with CSS and randomization too :)
About the scrolling up, it seems it’s an issue with CodePen when it’s embedded on other sites.
Great article! thats what i’d call some real css-tricks! :)
i wanted to try this out, so i made an animated die!
when hitting the dice a few times in a row I noticed it is actually going down al the time – from 6 to 0.
But if it is random I mean it should also show a 5 or a 6 at random. Right?
but it doesnt
Very nice! I tried doing something similar before (https://codepen.io/IAmAdamTaylor/pen/wqVaeP) but I couldn’t figure out the mouse down/ mouse up issue – brilliant solution by the way.
Side note: The codepen that is supposed to have the solution and faster animation time is the same as the one above it.