{ CF }

30 CSS Badges

Dice Face

A fair die with six possible states. Click to roll — the pip positions are correct, the animation is physical, the number updates. One honest square doing exactly one honest job.

CSS + JS MIT licensed

Dice Face the 18th of 30 designs in the 30 CSS Badges collection. The design pairs CSS styling with a small amount of JavaScript for interactivity. Copy the HTML, CSS and JavaScript panels below into your project — the JS is self-contained, has zero dependencies, and is safe to drop into any framework (React, Vue, Svelte, plain HTML). The design honours prefers-reduced-motion and uses real semantic markup, so it ships accessibility-ready out of the box.

Live preview

Open in playground

The code

<div class="die-stage">
  <div class="die-wrap">
    <div class="die-cube" id="die-cube">
      <div class="die-pip" data-pos="tl"></div>
      <div class="die-pip" data-pos="tc"></div>
      <div class="die-pip" data-pos="tr"></div>
      <div class="die-pip" data-pos="ml"></div>
      <div class="die-pip" data-pos="mc"></div>
      <div class="die-pip" data-pos="mr"></div>
      <div class="die-pip" data-pos="bl"></div>
      <div class="die-pip" data-pos="bc"></div>
      <div class="die-pip" data-pos="br"></div>
    </div>
  </div>
  <div class="die-face-num" id="die-face-num">—</div>
  <div class="die-caption">click the die to roll</div>
</div>
.die-stage {
  background: #fff;
  padding: 60px 48px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 24px;
  min-height: 360px;
}
.die-wrap { perspective: 600px; }
.die-cube {
  width: 110px;
  height: 110px;
  background: #fff;
  border: 2.5px solid #1a1612;
  border-radius: 18px;
  display: grid;
  grid-template-areas:
    "tl tc tr"
    "ml mc mr"
    "bl bc br";
  grid-template-columns: 1fr 1fr 1fr;
  grid-template-rows: 1fr 1fr 1fr;
  padding: 14px;
  cursor: pointer;
  box-shadow:
    4px 4px 0 #1a1612,
    5px 5px 8px rgba(0,0,0,0.12);
  transition: transform 0.15s, box-shadow 0.15s;
  position: relative;
  overflow: hidden;
}
.die-cube:active {
  transform: translate(3px, 3px);
  box-shadow: 1px 1px 0 #1a1612, 2px 2px 4px rgba(0,0,0,0.1);
}
.die-cube.is-rolling {
  animation: die-roll 0.5s cubic-bezier(0.36, 0.07, 0.19, 0.97);
}
@keyframes die-roll {
  0%   { transform: rotate(0deg) scale(1); }
  20%  { transform: rotate(-8deg) scale(0.95); }
  50%  { transform: rotate(12deg) scale(0.92); }
  75%  { transform: rotate(-5deg) scale(0.97); }
  100% { transform: rotate(0deg) scale(1); }
}
@media (prefers-reduced-motion: reduce) {
  .die-cube.is-rolling { animation: none; }
}
.die-pip {
  display: flex;
  align-items: center;
  justify-content: center;
}
.die-pip::after {
  content: '';
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: transparent;
  transition: background 0.2s;
}
.die-pip.is-on::after { background: #1a1612; }
.die-pip[data-pos="tl"] { grid-area: tl; }
.die-pip[data-pos="tc"] { grid-area: tc; }
.die-pip[data-pos="tr"] { grid-area: tr; }
.die-pip[data-pos="ml"] { grid-area: ml; }
.die-pip[data-pos="mc"] { grid-area: mc; }
.die-pip[data-pos="mr"] { grid-area: mr; }
.die-pip[data-pos="bl"] { grid-area: bl; }
.die-pip[data-pos="bc"] { grid-area: bc; }
.die-pip[data-pos="br"] { grid-area: br; }
.die-caption {
  font-family: system-ui, "Bricolage Grotesque", sans-serif;
  font-size: 11px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: #aaa;
  text-align: center;
}
.die-face-num {
  font-family: Georgia, "Fraunces", serif;
  font-size: 48px;
  font-style: italic;
  font-weight: 300;
  color: #1a1612;
  line-height: 1;
  text-align: center;
}
// Click the die to roll. Pip positions per face are encoded as
// arrays of grid-area names; the .is-on class lights up matching pips.
var dieFaces = {
  1: ['mc'],
  2: ['tr', 'bl'],
  3: ['tr', 'mc', 'bl'],
  4: ['tl', 'tr', 'bl', 'br'],
  5: ['tl', 'tr', 'mc', 'bl', 'br'],
  6: ['tl', 'tr', 'ml', 'mr', 'bl', 'br']
};
var dieCube    = document.getElementById('die-cube');
var dieFaceNum = document.getElementById('die-face-num');
var dieRolling = false;

function dieSetFace(n) {
  var pips = dieFaces[n];
  dieCube.querySelectorAll('.die-pip').forEach(function (p) {
    p.classList.toggle('is-on', pips.indexOf(p.dataset.pos) !== -1);
  });
  dieFaceNum.textContent = n;
}

if (dieCube) {
  dieCube.addEventListener('click', function () {
    if (dieRolling) return;
    dieRolling = true;
    dieCube.classList.add('is-rolling');
    setTimeout(function () {
      var n = Math.floor(Math.random() * 6) + 1;
      dieSetFace(n);
      dieCube.classList.remove('is-rolling');
      dieRolling = false;
    }, 280);
  });
}

Search CodeFronts

Loading…