三本線のメニューアイコンから×マークに変化するアニメーションいろいろ

CSSでアニメーションができるわけですし、どうせならちょっとアクセントをつけたいって感じのやつです。

#三本線から×に変化させる

いろいろアイデアありますね。

JavaScriptはクラス名を変更するためだけにちょろっと使ってるだけなのでシンプルです。
チェックボックスを活用したJavaScriptを完全に使わない方法もありますが割愛。

まず、以下のHTMLとCSSは共通で使用するものとします。

```html:HTML
<div class="menuWrapper">
  <a href="#menu" id="menuButton"><span>MENU</span></a>
</div>
```

```css:CSS
.menuWrapper {
  position: relative;
  z-index: 0;
  border: 1px solid #ccc;
  width: 50px;
  height: 50px;
}

#menuButton {
  overflow: hidden;
  display: block;
  position: relative;
  z-index: 0;
  width: 50px;
  height: 50px;
  cursor: pointer;
}

#menuButton span,
#menuButton::before,
#menuButton::after {
  display: block;
  position: absolute;
  top: 0;
  bottom: 0;
  left:0;
  right: 0;
  width: 36px;
  height: 4px;
  margin: auto;
  background: #000;
}
#menuButton span {
  overflow: hidden;
  z-index: 1;
  color: #000;
}
#menuButton::before {
  z-index: 2;
  transform: translate(0, -12px);
  content: "";
}
#menuButton::after {
  z-index: 2;
  transform: translate(0, 12px);
  content: "";
}
```

こんな感じの表示になります。

![sample.png](https://qiita-image-store.s3.amazonaws.com/0/169473/9db516f4-6e19-88d8-b976-4cc09cddb148.png)

##サンプル1

![sample1.gif](https://qiita-image-store.s3.amazonaws.com/0/169473/97be916b-d947-ccd4-12f0-6cb994e85ba0.gif)

→ [実際の動作サンプル1](https://sdn-project.net/sample/menu01.html)

```css:CSS
#menuButton span {
  opacity: 1;
  transition: opacity 150ms 50ms;
}
#menuButton::before,
#menuButton::after {
  transition: transform 200ms;
}

#menuButton.active span {
  opacity: 0;
  transition: opacity 150ms;
}
#menuButton.active::before {
  transform: rotate(45deg);
}
#menuButton.active::after {
  transform: rotate(-45deg);
}
```

```js:JavaScript
document.addEventListener('DOMContentLoaded', function () {
  document.getElementById('menuButton').addEventListener('click', function (ev) {
    ev.preventDefault();
    this.classList.toggle('active');
  });
});
```

##サンプル2

![sample2.gif](https://qiita-image-store.s3.amazonaws.com/0/169473/6d8d5b87-78a9-bba1-79e8-b3cf92fc7103.gif)

→ [実際の動作サンプル2](https://sdn-project.net/sample/menu02.html)

```css:CSS
#menuButton span {
  transition: transform 150ms 50ms;
}
#menuButton::before,
#menuButton::after {
  transition: transform 200ms;
}

#menuButton.active span {
  transform: translate(-50px, 0);
  transition: transform 150ms;
}
#menuButton.active::before {
  transform: rotate(45deg);
}
#menuButton.active::after {
  transform: rotate(-45deg);
}
```

```js:JavaScript
document.addEventListener('DOMContentLoaded', function () {
  document.getElementById('menuButton').addEventListener('click', function (ev) {
    ev.preventDefault();
    this.classList.toggle('active');
  });
});
```

##サンプル3

![sample3.gif](https://qiita-image-store.s3.amazonaws.com/0/169473/f633134d-5961-a6bc-4c94-6470b7696c93.gif)

→ [実際の動作サンプル3](https://sdn-project.net/sample/menu03.html)

```css:CSS
#menuButton {
  transition: transform 300ms;
}
#menuButton span {
  opacity: 1;
  transition: opacity 200ms;
}
#menuButton::before,
#menuButton::after {
  transition: transform 200ms;
}

#menuButton.active {
  transform: rotate(180deg);
}
#menuButton.active span {
  opacity: 0;
}
#menuButton.active::before {
  transform: rotate(45deg);
}
#menuButton.active::after {
  transform: rotate(-45deg);
}
```

```js:JavaScript
document.addEventListener('DOMContentLoaded', function () {
  document.getElementById('menuButton').addEventListener('click', function (ev) {
    ev.preventDefault();
    this.classList.toggle('active');
  });
});
```

##サンプル4

![sample4.gif](https://qiita-image-store.s3.amazonaws.com/0/169473/86e5c10a-66d1-3898-e2a2-6c438e55421d.gif)

→ [実際の動作サンプル4](https://sdn-project.net/sample/menu04.html)

```css:CSS
@keyframes lineTop {
  50% {
    transform: translate(0, 0);
  }
  100% {
    transform: rotate(45deg);
  }
}
@keyframes lineMiddle {
  50%, 100% {
    opacity: 0;
  }
}
@keyframes lineBottom {
  50% {
    transform: translate(0, 0);
  }
  100% {
    transform: rotate(-45deg);
  }
}

#menuButton.active span {
  animation: lineMiddle 250ms step-end forwards;
}
#menuButton.active::before {
  animation: lineTop 250ms forwards;
}
#menuButton.active::after {
  animation: lineBottom 250ms forwards;
}

#menuButton.default span {
  animation: lineMiddle 250ms step-end reverse;
}
#menuButton.default::before {
  animation: lineTop 250ms reverse;
}
#menuButton.default::after {
  animation: lineBottom 250ms reverse;
}
```

```js:JavaScript
document.addEventListener('DOMContentLoaded', function () {
  document.getElementById('menuButton').addEventListener('click', function (ev) {
    var classList = this.classList;
    ev.preventDefault();
    if (classList.contains('active')) {
      classList.remove('active');
      requestAnimationFrame(function () {
        classList.add('default');
      });
    } else {
      classList.remove('default');
      requestAnimationFrame(function () {
        classList.add('active');
      });
    }
  });
});
```

---

大きさやアニメーションの速度などいじって自分好みにカスタマイズしてみるといいかもしれません。