<div class="app">

  <h2>Bouncing toggles</h2>

  <!-- prototyping, This is not semantic HTML -->
  <div class="toggle" id="toggle-1">
    <div class="knot">
      <div></div>
      <div></div>
    </div>
  </div>

    <div class="toggle toggle--1" id="toggle-2">
    <div class="knot">
      <div></div>
      <div></div>
    </div>
  </div>
  
  
    <div class="toggle toggle--2" id="toggle-3">
    <div class="knot">
      <div></div>
      <div></div>
    </div>
  </div>

  
</div>
$size: 40px;
$width: 100px;

* {
  box-sizing: border-box;
}
body {
  font-family: Verdana, sans-serif;
  margin: 0;
  display: grid;
  place-items: center;
  min-height: 100vh;
  overflow: hidden;
}

.app {
  display: grid;
  place-items: center;
}

.toggle {
  width: $width;
  height: $size;
  box-shadow: 0 0 0 2px #333;
  border-radius: $size;
  overflow: hidden;
  transform: rotateZ(-5deg);
  margin-bottom: 2rem;
  cursor: pointer;
  outline: none;
  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
  &--1 {
    .knot {
      > :nth-child(1) {
        background: lightblue;
      }
      > :nth-child(2) {
        background: dodgerblue;
        box-shadow: inset 0 0 0 2px royalblue;
      }
    }
  }
  &--2 {
    .knot {
      > :nth-child(1) {
        background: pink;
      }
      > :nth-child(2) {
        background: hotpink;
        box-shadow: inset 0 0 0 2px deeppink;
      }
    }
  }
}

.knot {
  height: $size;
  width: $width;
  position: relative;
  > * {
    position: absolute;
    top: 0;
    height: inherit;
  }
  > :nth-child(1) {
    background: lightgreen;
    width: $width;
    left: calc(-100% + #{$size/2});
  }
  > :nth-child(2) {
    width: $size;
    background: #333;
    border-radius: 50%;
    left: 0;
  }
}
View Compiled
const eases = window.eases;
const FuzzyToggle = window.FuzzyToggle;

const width = 100;
const size = 40;


let onUpdate = (params, toggle) => {
  let isExpanding = params.motion === "expanding";
  let ease = isExpanding ? eases.expoOut : eases.expoIn;
  let bounce = isExpanding ? eases.bounceOut : eases.bounceIn;
  toggle.style.transform = `rotateZ(${-5 + ease(params.value) * 10}deg)`;
  let knot = toggle.querySelector(".knot");
  knot.style.transform = `translateX(${bounce(params.value) *
    (width - size)}px)`;
};

let onDone = params => {};
let onToggle = params => {};


let toggle1 = document.querySelector("#toggle-1");
let toggle2 = document.querySelector("#toggle-2");
let toggle3 = document.querySelector("#toggle-3");


let fuzzy1 = FuzzyToggle({
  onUpdate: params => onUpdate(params, toggle1),
  onDone,
  onToggle,
  duration: 1000,
});
let fuzzy2 = FuzzyToggle({
  onUpdate: params => onUpdate(params, toggle2),
  onDone,
  onToggle,
  duration: 700
});
let fuzzy3 = FuzzyToggle({
  onUpdate: params => onUpdate(params, toggle3),
  onDone,
  onToggle,
  duration: 2000
});


toggle1.addEventListener("click", fuzzy1.toggle);
toggle2.addEventListener("click", fuzzy2.toggle);
toggle3.addEventListener("click", fuzzy3.toggle);

setTimeout(fuzzy3.toggle, 500);
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://unpkg.com/@kunukn/fuzzytoggle@0.0.5/dist/FuzzyToggle.umd.js
  2. https://unpkg.com/eases-cdn@1.0.3/dist/eases.umd.min.js