AI CSS Animations

Dice Roll Animation

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.

Rolled a 5

HTML

<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>

CSS

@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;
  }
}

Customizing this snippet

  • Color: set --txt-color on the element or a parent. Currently previewing #3b82f6.
  • Font size: set --txt-size. Every other dimension is in em, so the whole thing scales together. Currently previewing 40px.
  • Speed: change the duration on the transition or animation shorthand. Staggered delays are relative, so they keep their rhythm.
  • Reduced motion: the rule at the end of the CSS turns the motion off for people who asked their OS for less of it. Keep it.

Similar text animations