Back to CSS Circular Menus Tactile Dial Pure CSS
Share
HTML
<div class="ccm-tac" role="toolbar" aria-label="Tactile Dial">
  <input type="radio" name="ccm-tac" id="ccm-tac-0" class="ccm-tac-r" hidden />
  <input type="radio" name="ccm-tac" id="ccm-tac-1" class="ccm-tac-r" hidden />
  <input type="radio" name="ccm-tac" id="ccm-tac-2" class="ccm-tac-r" hidden checked />
  <input type="radio" name="ccm-tac" id="ccm-tac-3" class="ccm-tac-r" hidden />
  <input type="radio" name="ccm-tac" id="ccm-tac-4" class="ccm-tac-r" hidden />
  <div class="ccm-tac-dial" aria-hidden="true">
    <div class="ccm-tac-mark"></div>
    <div class="ccm-tac-bevel"></div>
  </div>
  <div class="ccm-tac-arc" aria-hidden="true"></div>
  <label for="ccm-tac-0" class="ccm-tac-i" style="--p: 0" aria-label="Email"><span>✉</span></label>
  <label for="ccm-tac-1" class="ccm-tac-i" style="--p: 1" aria-label="Photos"><span>◇</span></label>
  <label for="ccm-tac-2" class="ccm-tac-i" style="--p: 2" aria-label="Cloud"><span>☁</span></label>
  <label for="ccm-tac-3" class="ccm-tac-i" style="--p: 3" aria-label="Portfolio"
    ><span>⊞</span></label
  >
  <label for="ccm-tac-4" class="ccm-tac-i" style="--p: 4" aria-label="Settings"
    ><span>⚙</span></label
  >
</div>
CSS
.ccm-tac {
  --rot: 0deg;
  position: relative;
  width: 280px;
  height: 240px;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  font-family: system-ui, sans-serif;
}

.ccm-tac-dial {
  position: absolute;
  bottom: 20px;
  left: 50%;
  width: 130px;
  height: 130px;
  margin-left: -65px;
  border-radius: 50%;
  background:
    repeating-conic-gradient(from 0deg, #c9cfd7 0deg, #8b929c 1deg, #c9cfd7 2deg),
    linear-gradient(180deg, #c9cfd7 0%, #2b2f3e 46%, #2b2f3e 54%, #b0b7c1 100%);
  background-blend-mode: overlay, normal;
  box-shadow:
    0 12px 24px rgba(0, 0, 0, 0.4),
    0 4px 8px rgba(0, 0, 0, 0.3),
    inset 0 1px 0 rgba(255, 255, 255, 0.3),
    inset 0 -2px 4px rgba(0, 0, 0, 0.4);
  transform: rotate(var(--rot));
  transform-origin: center;
  transition: transform 0.7s cubic-bezier(0.65, 0, 0.35, 1);
  z-index: 2;
}

.ccm-tac-bevel {
  position: absolute;
  inset: 12px;
  border-radius: 50%;
  background: radial-gradient(circle at 30% 30%, #e8ecf0, #6b7280 70%, #2b2f3e);
  box-shadow:
    inset 0 1px 2px rgba(255, 255, 255, 0.4),
    inset 0 -2px 4px rgba(0, 0, 0, 0.5);
}

.ccm-tac-mark {
  position: absolute;
  top: 8px;
  left: 50%;
  width: 4px;
  height: 16px;
  margin-left: -2px;
  background: linear-gradient(180deg, #fff, #94a3b8);
  border-radius: 2px;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
  z-index: 3;
}

.ccm-tac:has(#ccm-tac-0:checked) {
  --rot: -50deg;
}

.ccm-tac:has(#ccm-tac-1:checked) {
  --rot: -25deg;
}

.ccm-tac:has(#ccm-tac-2:checked) {
  --rot: 0deg;
}

.ccm-tac:has(#ccm-tac-3:checked) {
  --rot: 25deg;
}

.ccm-tac:has(#ccm-tac-4:checked) {
  --rot: 50deg;
}

.ccm-tac-arc {
  position: absolute;
  bottom: -40px;
  left: 50%;
  width: 250px;
  height: 250px;
  margin-left: -125px;
  border-radius: 50%;
  border: 1px dashed rgba(255, 255, 255, 0.08);
  pointer-events: none;
  -webkit-mask: linear-gradient(180deg, #000 0%, #000 50%, transparent 50%);
  mask: linear-gradient(180deg, #000 0%, #000 50%, transparent 50%);
}

.ccm-tac-i {
  position: absolute;
  bottom: calc(20px + 65px);
  left: 50%;
  width: 38px;
  height: 38px;
  margin: -19px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid rgba(255, 255, 255, 0.1);
  color: #94a3b8;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transform: rotate(calc((var(--p) - 2) * 25deg)) translateY(-125px);
  transform-origin: 50% 50%;
  transition:
    background 0.25s,
    color 0.25s,
    box-shadow 0.3s,
    border-color 0.25s,
    transform 0.25s;
  z-index: 4;
}

.ccm-tac-i span {
  font-size: 17px;
  line-height: 1;
  display: inline-block;
  transform: rotate(calc((var(--p) - 2) * -25deg));
}

.ccm-tac-i:hover,
.ccm-tac-i:focus-visible {
  background: rgba(255, 255, 255, 0.08);
  color: #fff;
  border-color: rgba(255, 255, 255, 0.25);
  transform: rotate(calc((var(--p) - 2) * 25deg)) translateY(-130px);
}

.ccm-tac:has(#ccm-tac-0:checked) [for="ccm-tac-0"],
.ccm-tac:has(#ccm-tac-1:checked) [for="ccm-tac-1"],
.ccm-tac:has(#ccm-tac-2:checked) [for="ccm-tac-2"],
.ccm-tac:has(#ccm-tac-3:checked) [for="ccm-tac-3"],
.ccm-tac:has(#ccm-tac-4:checked) [for="ccm-tac-4"] {
  background: rgba(255, 255, 255, 0.16);
  color: #fff;
  border-color: rgba(255, 255, 255, 0.5);
  box-shadow: 0 0 24px 6px rgba(255, 255, 255, 0.18);
  transform: rotate(calc((var(--p) - 2) * 25deg)) translateY(-132px);
}