button.btn-toggle(id="menu-toggle")
  .line
  .line
  .line
View Compiled
$toggle-size: 60px;
$toggle-line-color: dimgray;
$toggle-line-focus-color: black;
$toggle-line-size: $toggle-size/8;
$toggle-line-angle: 405deg;
$toggle-anim-speed: 0.9s;

body {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100vh;
  background-color: snow;
}

.btn-toggle {
  position: relative;
  display: flex;
  flex-direction: column;
  cursor: pointer;
  user-select: none;
  -webkit-tap-highlight-color: rgba(0,0,0,0);
  padding: 12px;
  background-color: transparent;
  border-color: transparent;
  outline: none;
  transform: translateZ(0);
  transition: transform 0.1s ease-out;
  
  &:active { transform: translateY(4px); }
  
  &:focus .line:after { 
    background-color: $toggle-line-focus-color;
  }
}

.line {
  display: block;
  width: $toggle-size;
  padding: $toggle-line-size/2;
  
  &:after {
    content: '';
    display: block;
    width: 100%;
    height: $toggle-line-size;
    background-color: $toggle-line-color;
    border-radius: 2px;
    transform: translateZ(0) rotate(0);
    transition: background-color 0.2s ease-out;
  }
    
  .open & {
    @for $i from 1 through 2 {
      &:nth-child(#{$i}) {
        animation: jump-#{$i} $toggle-anim-speed forwards ease;
        &:after {
          animation: line-#{$i} $toggle-anim-speed forwards ease-in-out;
        }
      }
    }
  }
  
  .close & {
    @for $i from 1 through 2 {
      &:nth-child(#{$i}) {
        animation: jump-#{$i} $toggle-anim-speed reverse ease;
        &:after {
          animation: line-#{$i} $toggle-anim-speed reverse ease-in-out;
        }
      }
    }
  }
  
  .open &,
  .close & {
    &:nth-child(3) {
      animation: jump-3 $toggle-anim-speed forwards ease-out;
    }
  }
}

@keyframes line-1 {
  10% { transform: translateZ(0) rotate(0) }
  80% { transform: translateZ(0) rotate($toggle-line-angle - 10) }
  90%, 100% { transform: translateZ(0) rotate($toggle-line-angle) }
}

@keyframes line-2 {
  10% { transform: translateZ(0) rotate(0) }
  20% { transform: translateZ(0) rotate(10deg) }
  90%, 100% { transform: translateZ(0) rotate(-$toggle-line-angle) }
}

@keyframes jump-1 {
  10% { transform: translateY(0) }
  50% { transform: translateY(-$toggle-line-size * 12) }
  90%, 100% { transform: translateY(-$toggle-line-size * 1) }
}

@keyframes jump-2 {
  10% { transform: translateY(0) }
  50% { transform: translateY(-$toggle-line-size * 10) }
  85%, 100% { transform: translateY(-$toggle-line-size * 3) }
}

@keyframes jump-3 {
  10% { transform: translateY(-$toggle-line-size*1) rotate(15deg) }
  30% { transform: translateY(-$toggle-line-size*4) rotate(-10deg) }
  50% { transform: translateY($toggle-line-size) rotate(5deg) }
  80% { transform: translateY(0) }
}

@keyframes glow {
  50% {
    box-shadow: rgba(lighten($toggle-line-color, 10%), 0.4) 0 0 2px 2px;
  }
}
View Compiled
const btn = document.getElementById("menu-toggle");
const lines = btn.querySelectorAll(".line");
const cls = { open: "open", close: "close" };
let btnClass = cls.open;

btn.addEventListener("click", () => {
  if (btn.classList.contains(cls.open)) {
    btn.classList.remove(btnClass);
    btnClass = cls.close;
  } else if (btn.classList.contains(cls.close)) {
    btn.classList.remove(btnClass);
    btnClass = cls.open;
  }

  void btn.offsetWidth;
  btn.classList.add(btnClass);
});

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.