私と水平スクロール。
あけましておめでとうございます。
KOです。
今回はサイトリメイクの忘備録!!!
半年前にとある企業とのコラボ企画で
プロモーション用のティザーサイトを作成させていただきました。
そのサイトは下にスワイプすると横にスクロールする仕組みになっています。
水平スクロールと呼ぶのだとか。
今回、追加修正した画像の量もどんどん多くなってきたので、
思い切ってリメイクしてみました。(まだ未完成なのですが笑)
するとjsのコード量が以前の半分に、、、、笑
数えてみると元々800行くらいあったコードも450行程になっていました。
半年たって気付ける様になったことがますます増えてきた証拠ですね!笑
忘備録として、その一部を記述していきます。
水平スクロールを自作に
元々水平スクロールの実現に利用していたモジュール「jinvertscroll」
(https://github.com/pixxelfactory/jInvertScroll)
こちらを自作することにしました。
大まかなイメージは以下の図の通りです。
1 2 3 4 5 6 |
let yOffsetBack = document.getElementById('back'); window.addEventListener('scroll', ()=> { let pos = Math.floor(window.pageYOffset); yOffsetBack.style.transform = "translate3d(-"+ pos +"px,0,0)"; }); |
window.pageYOffset
は垂直方向のスクロール量を取得するwindowプロパティーです。
つまりスクロールした分、div.backを左にトランスレイトします。
div.frontも同じ様に2n分スライドさせます。
あとはflexboxを利用してそれぞれのdivに要素を追加していきます。
・positionではなく、translate3dで指定したのは
この方がスマホのスクロールが非常に滑らかだったからです。
pageYOffset参考:
https://lab.syncer.jp/Web/API_Interface/Reference/IDL/Window/pageYOffset/
必要な要素の位置情報を自動計算
水平スクロールを実装するともっと面白いアニメーションをどんどん追加したくなりますよね(笑)
そこで立ちはだかる、発火のタイミング問題。
以下の様なちょっと面白いことをするのも一苦労ですね。
・スクロール量に応じて、アニメーションを発火させる
・現れるセクション(ページの様なdiv要素)ごとに 1/10 2/10 3/10 の様にページカウントさせる
・内部リンクの様に、指定した要素に移動する
今までは、以下の様に自分がフックしたい座標を手入力で入れておいて
指定した座標とスクロール量が重なったタイミングで発火させていました。
1 2 3 4 5 6 7 8 9 10 11 12 |
const posData = { sp:{ sec1: 0, sec2: 520, sec3: 1028, }, pc{ sec1: 0, sec2: 700, sec3: 1300, } } |
手入力だと、spとpcで分けて書かなくちゃいけないし、
要素のサイズが変更になると全てをちょっとづつ変更しないといけないですよね。。。
改修後
自動で計算させてキーと値に分ける。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
let idData = []; // 指定したidを持つ要素の相対距離(一番左(0,0)からの距離)を取得する関数 const getElementRectX = (elem) => { let elemRect = document.getElementById(elem).getBoundingClientRect() return elemRect.left; } //上の関数を使って、(要素,距離)を一対とした連想配列を作成 let RectData = {}; let result = idData.map((value) => { let k = value; let v = getElementRectX(value); RectData[k] = v; }) |
こうすることで、サイト内にあるidを指定すると、
id名と位置が対になって連想配列に格納されることになります。
例えば、
1 |
let idData = ["itemA","itemB","itemC","itemD","itemE","itemF"] |
とすれば
1 2 3 4 5 6 7 8 |
{ itemA: 208, itemB: 658, itemC: 908, itemD: 1358, itemE: 2008, itemF: 2408 } |
こんな感じのオブジェクトが帰ってきます!、、、、おおお!!
こうするとデバイスによって要素の幅が違っても気にしなくていいので便利です。
ちなみにgetBoundingCliendRect()は
ブラウザの表示領域の左上を(0, 0)として、そこからの相対位置を取得してくれる、というものです。
https://qiita.com/makoto1219/items/9d5b71a792025703cdea
上記の他にも、値を直接触る部分は一つの連想配列に格納したり
ほとんど似たような関数を一つにまとめて引数で操作できる様にしてみました。
コードの量がすくなくなると、可読性も上がって修正にかかる時間も少なくなって気分もいいです。(笑)
リリースのタイミングみながらちょっとづつ改良していきたいですね✨