- let states = ['off', 'on'];
- let n = states.length;
- let k = 0;

style
  - for(let i = 0; i < n; i++)
    | .wrap > :nth-of-type(#{i + 1}) { --i: #{i} }
.wrap(role='group' aria-label='switch' style=`--k: ${k}`)
  - for(let i = 0; i < n; i++)
    input(type='radio' name='o' id=`o${i}` checked=i === k)
    label(for=`o${i}`) #{states[i]}
View Compiled
@use 'sass:math';

$l: 1.25;
$d: 8em;
$p: 2em;
$b: .125em;
$a: 70deg;
$v: 50deg;
$s: 270deg - .5*$a;
$o: 4*$b;
$u: $d - 2*$o;
$r: .5*$u;
$g: #202020, #696969, #2f2f2f;
$t: .35s;

@property --a {
  syntax: '<angle>';
  initial-value: 0deg;
  inherits: false
}

body, div { display: grid }

body {
  margin: 0;
  min-height: 100vh;
  background: #3c3c3c
}

.wrap {
  grid-template: repeat(2, 1em)/ max-content $d + $p + $b;
  place-content: space-between end;
  place-self: center;
  border: solid $b transparent;
  padding: $p;
  width: $d; height: $d;
  border-radius: 50%;
  background: 
    radial-gradient(at calc(50% + .5*#{$b}) calc(50% + #{$b}), 
        #141414 calc(#{$r} - #{2*$b}), 
        transparent calc(#{$r} + #{2*$b})), 
    radial-gradient(closest-side, 
        nth($g, 3) calc(100% + -1*#{$b} + -1px), 
        transparent calc(100% + -1*#{$b})) content-box, 
    conic-gradient(from $s at calc(50% + -1*#{$b/math.sin(.5*$a)}), 
        nth($g, 3) $a, transparent 0) padding-box, 
    conic-gradient(from $s, 
        nth($g, 2), nth($g, 1) $a, transparent 0%) border-box, 
    linear-gradient(nth($g, 1), nth($g, 2)) content-box;
  font: 1em/ 1.25 ubuntu, sans-serif;
  
  > * {
    grid-area: calc(1 + var(--i))/ 1;
    cursor: pointer
  }
  
  &::before, &::after {
    --i: 0;
    --a: calc((2*var(--k) - 1)*#{$v - $a});
    --mask:
      conic-gradient(from #{90deg - .5*$v} at 0, 
            red #{$v}, transparent 0) 0/ 50% no-repeat, 
      linear-gradient(red, red) content-box;
    grid-area: 1/ 2/ span 2;
    place-self: center end;
    margin: $o - $p;
    padding: inherit;
    width: $u; height: $u;
    border-radius: inherit;
    transform: 
      rotate(var(--a)) 
      scale(calc(1 - var(--i)*#{3*$b/$u}));
    background: 
      linear-gradient(calc(-1*var(--a)), 
          hsl(0, 0%, calc(9% + var(--i)*12%)), 
          hsl(0, 0%, calc(41% - var(--i)*12%)));
    -webkit-mask: var(--mask);
            mask: var(--mask);
    transition: transform $t, --a $t;
    content: ''
  }
  
  &::after { --i: 1 }
}

input {
  z-index: 2;
  opacity: 0
}

label {
  --hl: 0;
  --not-sel: min(1, max(var(--k) - var(--i), var(--i) - var(--k)));
  --sel: calc(1 - var(--not-sel));
  place-self: center;
  padding: .125em .375em;
  border-radius: 7px;
  box-shadow: 0 0 0 calc(var(--hl)*2px) nth($g, 1);
  color: 
    hsl(calc(10 + var(--i)*60), 
        calc(var(--sel)*75%), 
        calc(39% + var(--sel)*20%));
  font-size: 1.5em;
  transition: color $t;
  
  &:hover, :focus + & { --hl: 1 }
}
View Compiled
addEventListener('change', e => {
  let _t = e.target;
  
  _t.parentNode.style.setProperty('--k', +_t.id.substring(1))
})
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.