WebCraft

offset-path: ray()

A dial laid out by ray()

CaveatA ray needs a point to start from, and engines have disagreed about which point. The current spec starts it at offset-position, which defaults to the centre of the containing block; earlier implementations started it wherever the element itself sat, so the same rule threw every tick off the dial. Setting offset-position: 50% 50% and also left: 50%; top: 50% makes both readings land on the same spot. closest-side measures to the containing block, so the dial needs a size of its own or every ray has length zero.

FallbackAn engine without offset-path would pile every tick in the middle, so the dial hides behind @supports not (offset-path: ray(0deg)) and the range input it is built on comes back as a plain slider. Keyboard and screen readers use that input in every case: arrow keys turn the dial, and dragging only ever writes to it. Where @property is missing the value still works, it just jumps instead of easing and the readout skips the numbers in between.

HTML + CSS
<div class="dial">
  <i class="tick"></i> <!-- 41 of them -->
  <input type="range" min="0" max="100">
</div>

@property --v {
  syntax: "<number>";
  inherits: true;
  initial-value: 0;
}

.tick {
  position: absolute; left: 50%; top: 50%;
  offset-position: 50% 50%;
  --a: calc(-135deg + var(--i) * 6.75deg);
  offset-path: ray(var(--a) closest-side);
  offset-distance: 94%;
  offset-rotate: auto;
  /* dim until the value reaches this tick */
  opacity: clamp(.14, (var(--v) * .4 - var(--i)
    + 1) * 4, 1);
}

Published