A die drops in tumbling, bounces twice with a squash on landing, and flickers through faces before it settles on five. Pips read a six-cell color strip, so a face is just a number.
Also known as: dice roll css, rolling dice animation, random number dice.
<div class="txt-dice-roll" aria-label="Rolled a 5"> <span class="txt-dice-roll-die" aria-hidden="true"><i></i><i></i><i></i><i></i><i></i><i></i><i></i></span> <span class="txt-dice-roll-result">Rolled a 5</span> </div>
@property --txt-dice-roll-f {
syntax: "<integer>";
initial-value: 5;
inherits: true;
}
.txt-dice-roll {
--c: var(--txt-color, #3b82f6);
font-size: var(--txt-size, 32px);
font-family: system-ui, sans-serif;
font-weight: 700;
line-height: 1.2;
display: inline-flex;
align-items: center;
gap: 0.6em;}
.txt-dice-roll-die {
display: grid;
grid-template: repeat(3, 1fr) / repeat(3, 1fr);
gap: 0.1em;
width: 2.2em;
height: 2.2em;
padding: 0.32em;
border-radius: 0.42em;
background: var(--c);
box-shadow: inset 0 -0.1em 0 color-mix(in srgb, var(--c) 70%, #000), 0 0.12em 0.3em -0.1em rgb(0 0 0 / 0.4);
animation:
txt-dice-roll-tumble 1.3s forwards,
txt-dice-roll-faces 1.1s step-end forwards;
}
/* pips: top left, top right, middle left, center, middle right, bottom left, bottom right */
.txt-dice-roll-die i {
border-radius: 50%;
background-size: 600% 100%;
background-position: calc((var(--txt-dice-roll-f) - 1) * 100% / 5) 0;
}
.txt-dice-roll-die i:nth-child(1) { grid-area: 1 / 1; background-image: linear-gradient(90deg, transparent 0% 16.67%, #fff 16.67% 100%); }
.txt-dice-roll-die i:nth-child(2) { grid-area: 1 / 3; background-image: linear-gradient(90deg, transparent 0% 50%, #fff 50% 100%); }
.txt-dice-roll-die i:nth-child(3) { grid-area: 2 / 1; background-image: linear-gradient(90deg, transparent 0% 83.33%, #fff 83.33% 100%); }
.txt-dice-roll-die i:nth-child(4) { grid-area: 2 / 2; background-image: linear-gradient(90deg, #fff 0% 16.67%, transparent 16.67% 33.33%, #fff 33.33% 50%, transparent 50% 66.67%, #fff 66.67% 83.33%, transparent 83.33% 100%); }
.txt-dice-roll-die i:nth-child(5) { grid-area: 2 / 3; background-image: linear-gradient(90deg, transparent 0% 83.33%, #fff 83.33% 100%); }
.txt-dice-roll-die i:nth-child(6) { grid-area: 3 / 1; background-image: linear-gradient(90deg, transparent 0% 50%, #fff 50% 100%); }
.txt-dice-roll-die i:nth-child(7) { grid-area: 3 / 3; background-image: linear-gradient(90deg, transparent 0% 16.67%, #fff 16.67% 100%); }
.txt-dice-roll-result {
font-size: 0.8em;
font-weight: 700;
color: var(--c);
opacity: 0;
animation: txt-dice-roll-show 0.4s ease-out 1.25s forwards;
}
@keyframes txt-dice-roll-tumble {
0% { transform: translateY(-1.1em) rotate(-280deg) scale(0.8); animation-timing-function: cubic-bezier(0.55, 0, 1, 0.45); }
35% { transform: translateY(0) rotate(-110deg) scale(1); animation-timing-function: cubic-bezier(0, 0.55, 0.45, 1); }
52% { transform: translateY(-0.45em) rotate(-40deg); animation-timing-function: cubic-bezier(0.55, 0, 1, 0.45); }
68% { transform: translateY(0) rotate(-8deg) scale(1.1, 0.9); animation-timing-function: ease-out; }
80% { transform: translateY(-0.08em) rotate(-2deg) scale(0.97, 1.03); }
100% { transform: none; }
}
@keyframes txt-dice-roll-faces {
0% { --txt-dice-roll-f: 3; }
12.5% { --txt-dice-roll-f: 6; }
25% { --txt-dice-roll-f: 2; }
37.5% { --txt-dice-roll-f: 4; }
50% { --txt-dice-roll-f: 1; }
62.5% { --txt-dice-roll-f: 6; }
75% { --txt-dice-roll-f: 3; }
87.5% { --txt-dice-roll-f: 2; }
100% { --txt-dice-roll-f: 5; }
}
@keyframes txt-dice-roll-show {
from { opacity: 0; transform: translateX(-0.3em); }
to { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
.txt-dice-roll, .txt-dice-roll *, .txt-dice-roll::before, .txt-dice-roll::after, .txt-dice-roll *::before, .txt-dice-roll *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}--txt-color on the element or a parent.
Currently previewing #3b82f6.--txt-size. Every other dimension is in
em, so the whole thing scales together. Currently previewing 40px.transition or animation
shorthand. Staggered delays are relative, so they keep their rhythm.