フローティングボタンのアニメーションをCSSで作った

2022/10/27に公開

はじめに

初めまして、ポートのフロントエンドを担当している @fujita です。
業務で CSS アニメーションを使ったアニメーションの実装を行なったのでそれについて書いていこうと思います。

完成品

解説

CSS で装飾する

HTML は以下の通りです。こちらを SCSS で装飾していきます。

html
<button class="btn" type="button">
  <span class="dot"></span>
  <span class="rod1"></span>
  <span class="rod2"></span>
  <span class="rod3"></span>
</button>

SCSS は下記の通りです。

scss
.btn {
  border: 3px solid blue;
  border-radius: 50%;
  bottom: 30px;
  height: 60px;
  position: fixed;
  right: 30px;
  width: 60px;
  background-color: #fff;
}

.dotは左側真ん中の点の style を指定しています。擬似要素では左側上下の点の style を指定しています。

scss
.dot,
.dot::after,
.dot::before {
  background-color: blue;
  border-radius: 50%;
  content: '';
  height: 5px;
  position: absolute;
  width: 5px;
}

.dot {
  left: 14px;
  top: 24.5px;

  &::before {
    left: 0;
    top: 8px;
  }

  &::after {
    bottom: 8px;
    left: 0;
  }
}

.rodは右側真ん中の棒の style を指定しています。擬似要素では右側上下の棒の style を指定しています。

scss
.rod1,
.rod2,
.rod3 {
  background-color: blue;
  border-radius: 10px;
  content: '';
  display: block;
  height: 5px;
  position: absolute;
  width: 18px;
}

.rod1 {
  right: 13px;
  top: 17px;
}

.rod2 {
  right: 13px;
  top: 24.5px;
}

.rod3 {
  bottom: 16px;
  right: 13px;
}

ここまでの HTML、CSS で基本の表示は完成になります。

アニメーションを実装する

animation プロパティは複数のプロパティの一括指定プロパティで、アニメーションを適用することができます。
下記ではanimation-nameanimation-durationanimation-fill-modeを指定しています。

animation-name
使用したい@keyframesアットルールの名前を指定します。
animation-duration
1 回のアニメーション周期が完了するまでの所要時間を設定します。
animation-fill-mode
CSS アニメーションの実行の前後に対象にスタイルを適用するかを設定します。今回はforwardsを指定して@keyframes で設定した最後のキーフレームの計算値を保持しています。

scss
.close > .rod1 {
  animation: rod-close1 .75s forwards;
}

.close > .rod2 {
  animation: rod-close2 .75s forwards;
}

.close > .rod3 {
  animation: rod-close3 .75s forwards;
}

.close > .dot {
  animation: dot-close .75s forwards;
}

.open > .rod1 {
  animation: rod-open1 .75s forwards;
}

.open > .rod2 {
  animation: rod-open2 .75s forwards;
}

.open > .rod3 {
  animation: rod-open3 .75s forwards;
}

.open > .dot {
  animation: dot-open .75s forwards;
}

@keyframesアットルールは下記のような構文で CSS アニメーションの中間ステップを制御することができます。

css
@keyframes slidein {
  from {
    transform: translateX(0%);
  }

  to {
    transform: translateX(100%);
  }
}

from は0%を表し、to は100%を表します。今回は中間地点も指定するのでわかりやすく0%100%で指定しています。

scss
@keyframes dot-close {
  0% {
    opacity: 1;
  }

  30% {
    opacity: 1;
  }

  31% {
    opacity: 0;
  }

  100% {
    opacity: 0;
  }
}

@keyframes dot-open {
  0% {
    opacity: 0;
  }

  70% {
    opacity: 0;
  }

  71% {
    opacity: 1;
  }

  100% {
    opacity: 1;
  }
}

@keyframes rod-close1 {
  0% {
    width: 18px;
  }

  30% {
    transform: none;
    width: 27px;
  }

  70% {
    transform: translateY(8px) rotate(0deg);
  }

  100% {
    transform: translateY(8px) rotate(45deg);
    width: 27px;
  }
}

@keyframes rod-open1 {
  0% {
    transform: translateY(8px) rotate(45deg);
    width: 27px;
  }

  30% {
    transform: translateY(8px) rotate(0deg);
  }

  70% {
    transform: none;
    width: 27px;
  }

  100% {
    width: 18px;
  }
}

@keyframes rod-close2 {
  0% {
    opacity: 1;
    width: 18px;
  }

  30% {
    width: 27px;
  }

  69% {
    opacity: 1;
  }

  70% {
    opacity: 0;
  }

  100% {
    opacity: 0;
    width: 27px;
  }
}

@keyframes rod-open2 {
  0% {
    opacity: 0;
    width: 27px;
  }

  30% {
    opacity: 0;
  }

  31% {
    opacity: 1;
  }

  70% {
    width: 27px;
  }

  100% {
    opacity: 1;
    width: 18px;
  }
}

@keyframes rod-close3 {
  0% {
    width: 18px;
  }

  30% {
    transform: none;
    width: 27px;
  }

  70% {
    transform: translateY(-8px) rotate(0deg);
  }

  100% {
    transform: translateY(-8px) rotate(-45deg);
    width: 27px;
  }
}

@keyframes rod-open3 {
  0% {
    transform: translateY(-8px) rotate(-45deg);
    width: 27px;
  }

  30% {
    transform: translateY(-8px) rotate(0deg);
  }

  70% {
    transform: none;
    width: 27px;
  }

  100% {
    width: 18px;
  }
}

JavaScript でアニメーションを発火させる

JavaScript は下記の通りです。
addEventListenerメソッドを使用して btn をクリックしたら btn の class を付け替えるようにしています。

js
const btn = document.querySelector('.btn');

btn.addEventListener('click', () => {
  if (btn.classList.contains('close') === false) {
    btn.classList.add('close');
    btn.classList.remove('open');
  } else {
    btn.classList.remove('close');
    btn.classList.add('open');
  }
});

完成

以上の方法でフローティングボタンのアニメーションを実装しました。

参考文献

https://developer.mozilla.org/ja/docs/Web/CSS/animation
https://developer.mozilla.org/ja/docs/Web/CSS/animation-name
https://developer.mozilla.org/ja/docs/Web/CSS/animation-duration
https://developer.mozilla.org/ja/docs/Web/CSS/animation-fill-mode

Discussion