parallax(パララックス)でカーソルに合わせて斜めにスライドさせたい

こんにちは、今日はタイトルの通りparallaxでカーソルに合わせて斜めにスライドする方法をご紹介します。

ではまずはデモから!
スクロールしていくとスクロールに合わせて斜めに画像がスライドしていきます。

See the Pen
Untitled
by sayuri (@giraffeweb)
on CodePen.0

今回これを実装するにあたって、サンプルにできるブログやサイトなどがなく
頭の中では実装できても、実際のソースをひとりで実装することができませんでした。
そこでエンジニアさんの協力を得てなんとか実装することができましたので備忘録として残しておこうと思います。
ではそれぞれのソースと解説です。

▼HTML
今回は3つのブロックを斜めにしてスライドさせたかったので大まかに大きなdivブロックを3つ作成して
その中に画像を1ブロックに対し8枚程度並べています。

<section id="indexWork">
<div class="workWrap">
        <div id="work01" class="workBox"> //ブロック1つ目
            <div class="workBoxIn flex">
                <article> //1枚目
                    <picture>
                        <source>
                        <img src="https://i.postimg.cc/pdNMqXKP/05.jpg" alt="">
                    </picture>
                </article>
                <article> //2枚目
                    <picture>
                        <source>
                        <img src="https://i.postimg.cc/fk4VwQ6Z/02.jpg" alt="">
                    </picture>
                </article>
                <article> //3枚目
                    <picture>
                        <source>
                        <img src="https://i.postimg.cc/pdNMqXKP/05.jpg" alt="">
                    </picture>
                </article>
                <article> //4枚目
                    <picture>
                        <source>
                        <img src="https://i.postimg.cc/fk4VwQ6Z/02.jpg" alt="">
                    </picture>
                </article>
                 <article> //5枚目
                    <picture>
                        <source>
                        <img src="https://i.postimg.cc/pdNMqXKP/05.jpg" alt="">
                    </picture>
                </article>
                <article> //6枚目
                    <picture>
                        <source>
                        <img src="https://i.postimg.cc/fk4VwQ6Z/02.jpg" alt="">
                    </picture>
                </article>
                <article> //7枚目
                    <picture>
                        <source>
                        <img src="https://i.postimg.cc/pdNMqXKP/05.jpg" alt="">
                    </picture>
                </article>
                <article> //8枚目
                    <picture>
                        <source>
                        <img src="https://i.postimg.cc/fk4VwQ6Z/02.jpg" alt="">
                    </picture>
                </article> 
            </div>
        </div>

        <div id="work02" class="workBox"> //ブロック2つ目
            <div class="workBoxIn flex">
                <article>
                    <picture>
                        <source>
                        <img src="https://i.postimg.cc/pdNMqXKP/05.jpg" alt="">
                    </picture>
                </article>
                ・・・省略・・・
            </div>
        </div>
        
        <div id="work03" class="workBox"> //ブロック3つ目
            <div class="workBoxIn flex">
                <article>
                    <picture>
                        <source>
                        <img src="https://i.postimg.cc/fk4VwQ6Z/02.jpg" alt="">
                    </picture>
                </article>
                ・・・省略・・・
            </div>
        </div>
    </div>
  </section>

▼CSS
CSSは主にコメントしているところが重要なところです。
スピードなどは自由に変更してください。
画像の傾きを変更する場合は、のちほどJSを触る必要があるので数字を覚えておいてくださいね。

.workWrap {
        background-color: rgba($black,.6);
        width: 100%;
        height: 100vh;
        overflow: hidden;
        .workBox {
            transform: rotate(20deg); //画像の傾き
            transform-origin: left; //左側を回転軸に
            width: 400%; //3つのブロックの横幅を大きくとっておく
            transition: all 1.5s ease-out; //スクロールしたときにスムーズにparallaxする
            &#work01 {
                margin: -80vh 0 0 0;
            }
            &#work01,&#work02,&#work03 {
                position: relative;
            }
            .workBoxIn {
                position: relative;
                article {
                    width: 20%; //一つのサイズの横幅
                    padding: 3vw 2vw;
                    picture {
                        display: block;
                        overflow: hidden;
                        width: 100%;
                        aspect-ratio: 4 / 1.8; //画像の比率はここで調整
                        img {
                            max-width: 110%; //ここで少し大きめに画像をとっておく
                            width: 110%; //ここで少し大きめに画像をとっておく
                            position: relative;
                            transition: all 1.5s ease-in-out;
                        }
                    }
                }
            }
   }
}

▼javascript

今回はサイト実装時にわけあってjQueryを使用せずにjavascriptのみでソースを書いています。
円周率やタンジェントの計算もあり、私ひとりではどうにもこうにも実装できませんでした。

コメントで簡単な説明文だけ記載しています。

document.addEventListener('DOMContentLoaded', function() {
  const w1 = document.getElementById('work01'); //ブロック1つめ
  const w2 = document.getElementById('work02'); //ブロック2つめ
  const w3 = document.getElementById('work03'); //ブロック3つめ
  const tangent = Math.tan(20 * Math.PI / 180); //ここの20はCSSで傾けた回転度数
  const speed = .3;  // スライド速度 (スクロール量に対するスライド量の比率)

  const imgs1 = w1.getElementsByTagName('img');
  const imgs2 = w2.getElementsByTagName('img');
  const imgs3 = w3.getElementsByTagName('img');
  const prlx_vol = 50;  // パララックスで画像が動く量の調節。値が低いほどよく動く。50以上推奨

  window.addEventListener("scroll", function () {

    let scr_start = document.getElementsByClassName('workWrap')[0].getBoundingClientRect().top + window.pageYOffset - window.innerHeight; // 画面上端からworkWrapまでの距離
    let slide = (window.scrollY - scr_start) * speed;
    let prlx_rate = slide / prlx_vol;
    let img_w = document.getElementsByClassName('workBoxIn')[0].getElementsByTagName('article')[0].offsetWidth;
    let offset = img_w * 3;  // 画像N枚分あらかじめ左寄せ

    if (slide > 0 && scr_start > 0) {
      w1.style.left = (slide - offset) + 'px';
      w1.style.top = (slide - offset) * tangent + 'px';
      w2.style.left = -(slide) + 'px';
      w2.style.top = -(slide) * tangent + 'px';
      w3.style.left = (slide - offset) + 'px';
      w3.style.top = (slide - offset) * tangent + 'px';
    }

    // パララックス 画像の移動範囲を制限:max-width:110%なので10%ぶん
    if (prlx_rate > 0 && prlx_rate < 10) {
      for (let i = 0; i < imgs1.length; i++) {
        imgs1[i].style.left = - prlx_rate + '%';
        imgs2[i].style.left = prlx_rate - 10 + '%';
        imgs3[i].style.left = - prlx_rate + '%';
      }
    }
  });
});

JS部分本当はもっと詳しく書きたかったんですが、眠気に勝てないのでこの辺で!
また時間があるときに追記で詳しく書いておこうと思います。

それでは~