LoginSignup
0
0

More than 3 years have passed since last update.

スクロールすると要素が揺れるページを作る

Posted at

最初はJSのみで実装しようと思いましたが、難しくて挫折。CSSアニメーションを使えばかなり簡単に作れましたー。ちなみに、ライブラリは使っていません。

何かしら良さげなライブラリがありそうですが、パッと見た感じなさそうなので作ってみました。

HTMLは必要最低限。

HTML

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>trace huuuu</title>
  <link rel="stylesheet" href="style.css">
</head>
<body style="height: 200vh; width: 100vw;">
  <div class="shakes"></div>
  <div class="shakes"></div>
  <div class="shakes"></div>
  <div class="shakes"></div>
  <div class="shakes"></div>
  <div class="shakes"></div>
  <script src="script.js"></script>
</body>
</html>

揺らす要素にshakesというクラスを付けています。
transform-origin: 50% 0;と書いておくと、揺れてる感が出て良き良き。

CSS

.shakes {
  width: 200px;
  height: 100px;
  margin: 150px;
  transform-origin: 50% 0;
  background-color: pink;
}

正直JSはコードに自信がないので晒したくはないのですが、ひとまず下記のような感じにしてみました。

各要素ごとに、振幅にばらつきがあったり、振れの速度が違った方が面白いので、それぞれランダムな値を持たせています。

JavaScript

let oldPos = 0;
let timeoutId = 0;
let scrolls = [];
let minShakeAngle = 0.3; // 最小振れ角
let attenuation = 0.8; // 振幅減衰率
let defaultAngle = 45; // 基準振れ角

window.onload = () => {
  oldPos = window.scrollY;
  let shakes = Array.from(document.getElementsByClassName('shakes'));
  shakes.forEach((shake, index) => {
    scrolls.push(new Scroll(shake));
  });

  window.addEventListener( "scroll", () => {
    clearTimeout( timeoutId );
    let timeoutId = setTimeout( function () {
      let distance = Math.abs(window.scrollY - oldPos);
      let angleRate = distance / (document.body.clientHeight - window.innerHeight);
      let angle = angleRate * defaultAngle;
      scrolls.forEach((scroll) => {
        scroll.shakeSet(angle);
      });
      oldPos = window.scrollY;
    }, 15);
  });
}

class Scroll {
  constructor(el) {
    this.el = el; // 要素
    this.currentAngle = 0; // 現在の振れ角
    this.add = 1; // 振れ方向の正負
    this.animationId;
    this.animateFlg = false; // 振れているかどうか
    this.angleRate = Math.random() + 0.5; // 要素ごとの振れ角のばらつき
    this.animationInterval = 200 * Math.random() + 500; // 要素ごとの振れ速度
    // 要素ごとに振れ速度を変えて、
    el.style.transition = `transform ${this.animationInterval}ms ease-in-out`;
    // インスタンス生成時に要素を揺らしています。
    this.shakeSet(10);
  }

  shakeSet(angle) {
    angle *= this.angleRate;
    if(this.currentAngle < angle) {
      this.currentAngle = angle;
      if(!this.animateFlg) {
        this.animateFlg = true;
        this._shake();
      }
    }
  }

  _shake() {
    this.animationId = setInterval(() => {
      this.el.style.transform = `rotate(${this.currentAngle * this.add}deg)`;
      this.add = this.add * -1;
      if(this.currentAngle < minShakeAngle) {
        this.el.style.transform = `rotate(0deg)`;
        clearInterval(this.animationId);
        this._clearVariable();
        return;
      }
      this.currentAngle *= attenuation;
    }, this.animationInterval);
  }

  _clearVariable() {
    this.add = 1;
    this.currentAngle = 0;
    this.animateFlg = false;
  }
}

動作は下記URLより

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0