Funky button

Button with randomized clipping, animated on hover/focus.

HTML

<button><span>Funky button!</span></button>

CSS

@import url('https://fonts.googleapis.com/css2?family=ZCOOL+KuaiLe&display=swap');

:root {
  --color-page-background: #45b5f3;
  --color-link-background: white;
  --color-link-shadow: #0081c7;
  --funky-button-width: 240px;
  --funky-button-height: 70px;
}

body {
  background-color: var(--color-page-background);
  padding: 1em;
  font-family: 'ZCOOL KuaiLe', Verdana, Geneva, Tahoma, sans-serif;
  font-size: 20px;
  font-weight: bold;
  letter-spacing: 1px;
}

button {
  --clip: polygon(
    var(--clip-offset-1, 0px) var(--clip-offset-2, 0px),
    calc(100% - var(--clip-offset-3, 0px)) var(--clip-offset-4, 0px),
    calc(100% - var(--clip-offset-5, 0px)) calc(100% - var(--clip-offset-6, 0px)),
    var(--clip-offset-7, 0px) calc(100% - var(--clip-offset-8, 0px))
  );
  position: relative;
  background: unset;
  border: none;
  width: var(--funky-button-width);
  height: var(--funky-button-height);
  display: flex;
  align-items: center;
  justify-content: flex-start;
  padding-left: 1.5em;
  font: inherit;
  outline: none;
  cursor: pointer;
}

button::before,
button::after {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  background-color: var(--color-link-background);
  clip-path: var(--clip);
  z-index: -1;
}

button::before {
  background-color: var(--color-link-shadow);
  transform: translate3d(7px, 5px, 0px);
}

button span {
  display: inline-block;
}

button:is(:hover, :focus-visible)::after,
button:is(:hover, :focus-within) span {
  transform: translate3d(-2px, -2px, 0px) scale(1.02);
}

button:is(:hover, :focus-visible)::before {
  transform: translate3d(7px, 6px, 0px) scale(1.02);
}

JavaScript

const shuffle = (arr) => {
  for (let i = arr.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [arr[i], arr[j]] = [arr[j], arr[i]];
  }
  return arr;
}

const randomizeClipOffsets = (selector, offsets = [0, 0, 1, 3, 3, 4, 5, 6]) => {
  for (const element of document.querySelectorAll(selector)) {
    let index = 0;
    for (const offset of shuffle(offsets.slice())) {
      element.style.setProperty(`--clip-offset-${++index}`, `${offset}px`);
    }
  }
}

const init = () => {
  randomizeClipOffsets('button');
  setInterval(randomizeClipOffsets, 350, 'button:is(:hover, :focus-visible)');
}

init();