Vanilla JSのパララックス実装ライブラリ「Rellax」が使いやすくなるoptional設定

#はじめに
私はプログラミングを学習して3ヶ月の初学者であり、今回が**初投稿**(大事)になります。
22歳の**文系大学既卒未経験**(大事)で、エンジニア目指して勉強/就活中の身です。

「クソ記事を量産するな！」と言われそうですが、学習の中でつまづいた点に関して日本語で書かれたドキュメントが見受けられず時間を食われたため、一発書いてみようかなと思い立ちました。

突っ込みどころ満載かもしれませんが、あらかじめご了承ください。
誤った情報や記述等がありましたらご指摘ください。

#なんの記事
JSライブラリ**「Rellax」**を使ってみて、使いづらさを感じた点がありました。
そのもやもやを解決するまでの軌跡をまとめた記事になります。ライブラリをまともに扱うのも初めて。

#Rellax
- **「Rellax」**とは、軽量かつVanillaJSにてパララックス効果（視差効果）を実装できるライブラリです。
実装方法など詳細は割愛させていただきます（非常に簡単です）。
[（参考リンク）](https://webkore.site/rellax/)

公式HPリンク:
[Vanilla Javascript Parallax Library — Rellax - Dixon & Moe](https://dixonandmoe.com/rellax/)
githubリンク:
[github](https://github.com/dixonandmoe/rellax)

#使いづらさを感じた点
さて本題に入ります。

Rellaxのデフォルト設定では、パララックス要素の監視対象はbody要素になります。
そのため、それぞれの対象要素の位置はbody要素のscrollTopからの距離によって計算され決まります。
(参考)

```rellax.js
// 246~248行目
// If the element has the percentage attribute, the posY and posX needs to be 
// the current scroll position's value, so that the elements are still positioned based on HTML layout
       var wrapperPosY = self.options.wrapper ? self.options.wrapper.scrollTop : (window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop);
```

そのため、パララックス要素とページ最上部との距離の差は大きな挙動の差異を生みます。
この仕様がなんとも使いにくい...

今回は、そんなRellaxの挙動がわかりやすいようにCodepenにて書いてみました。
Codepenのスマートさに感動。

- [Rellaxの挙動テスト - Codepen](https://codepen.io/dendai-man/pen/qBOBRBZ)

ご覧のように、縦のmarginや対象要素のサイズなど**body.scrollTopからの高さに影響を与えるプロパティの全て**がパララックスの挙動に影響します。
（他のパララックスライブラリは使用したことがないので分かりませんが、全てがこのような仕様なのでしょうか。）

お陰さまでCSSでのデザイン調整に四苦八苦。
パララックスを与えたい要素にposition:absoluteの要素が多めだったのですが、topやらmargin-topやらheightやらで微調整をひたすら繰り返し。計500vh程あるサイトだったこともあり私の脳は間も無く限界を迎えました。

####「監視領域をbodyではなく、独自の要素に適用できれば楽なのに・・・！」

#まず試したこと
- Read.meに書かれていたオプションを改めて見直してみました。

(図は上記リンク記事から拝借)

| オプション名       |      オプション内容 | デフォルト値    |
|:-----------------|-----------------|------------------|
| speed            |           スピード ( -10 ~ 10 ) | -2       |
| center           |         センタリング | false |      |
| wrapper           |             監視領域 | null (body)        |
| round               |   公式解説なし | 公式解説なし         |
| vertical             |       Y方向パララックス       |       true      |
| horizontal          |   X方向パララックス        |      false       |

一見して使えそうだったのは**center**と**wrapper**オプション。
早速試してみました。

###centerオプション

→Viewport内でのセンタリングを行うものでした。
~~非常に便利なオプションなのですが、私の場合なぜか挙動がおかしくなり、原因もわからず。
今回はスルーしました。~~
- **挙動がおかしい原因は、centeringさせたい要素の親要素にrellaxを適用させていたためでした。このオプションをうまく使えば当初やりたかったことは解決できることに気がつきました。この記事いる...？**
- //4/11　追記：
- (data-rellax-percentage="0~1"という指定があり、このcenterオプションをtrueにすると全ての要素にdata-rellax-percentage="0.5"が付与されます。なお、center:trueにしてしまうと全ての値が0.5で上書きされるので、個別でpercentageを適用することができくなってしまいます。)**

###wrapperオプション
→期待を寄せていたのはこのオプションでした。wrapper要素を指定すれば、その要素が監視対象、つまり起点となり位置計算が行われるのでは！？...と。

>**Custom Wrapper**
By default, the position of parallax elements is determined via the scroll position of the body. Passing in the wrapper property will tell Rellax to watch that element instead.

>>`<script>
  // Set wrapper to .custom-element instead of the body
  var rellax = new Rellax('.rellax', {
    wrapper: '.custom-element'
  });
</script>`

####→結果
思っていたように動かず。
このwrapperでは確かに独自の監視領域を設定できるのですが、まず**複数の監視領域は設けられない**ことが判明。
さらにwrapper要素は、overflow:autoなどのプロパティが付与された**スクローラブルな要素**でないといけませんでした。うむむ。
(こちらもCodepenで試してみました。確認してみてください。)

- [Codepenでの検証 ー リンク](https://codepen.io/dendai-man/pen/mdedOyJ)



#次に試したこと
諦めきれず、githubのissueを読み漁りました。初めて読みました。笑

まず見つけたのがRead.meには記載のなかったオプション**relativeToWrapper**でした。

- [参考githubリンク](https://github.com/dixonandmoe/rellax/pull/125)

このオプション値をtrueにすると、windowからではなくwrapperに設定した要素からのスクロールポジションによって相対位置が計算されます。
**※オプション値の設定だけでなく、js側へ以下の記述が必要になります。(refreshなしだと1度しか発火しない)**

` window.addEventListener('scroll', function () {
    parallax.refresh()
  })`

- [検証用Codepenリンク](https://codepen.io/dendai-man/pen/abvbGea)

####→実際に監視領域をこちら側で設定することができました。

しかし！　このオプションによって監視領域の位置をこちらで決められるようになりましたが、対象領域を複数生成することは出来ず。まだ腑に落ちません。

#そして解決へ
最終的な解決へ導いてくれたのが、以下のissueに書かれていたコードになります。

- [Set wrapper to parent element #141](https://github.com/dixonandmoe/rellax/issues/141)

```main.js
//　パララックス対象要素のDOMを全て取得
const rellaxin = document.querySelectorAll(".rellax");
//　それぞれの親要素にrelativeなwrapperを付与
rellaxin.forEach(el => {

  const rellax = new Rellax(el, {
    relativeToWrapper: true,
    wrapper: el.parentElement
  });
// バグfix
  window.addEventListener("scroll", () => { // fix to init
    rellax.refresh();
  });

});
```

このコードによって、**指定したパララックス要素(ここでは.rellax)全ての親要素に対してrelativeWrapperを付与する**ことが出来ました。意外とシンプル！！
おかげ様で格段にスタイル調整がしやすくなりました。
####や、やったー！

#最後に
今回、初めての経験ばかりでした。Codepenを動かしたり、githubを見漁ったり。
楽しかったです。
Quitaに関しても初投稿になるので、引用やリンクの貼り方・書き方等ご指摘ありましたらお願いします。
お読みいただきありがとうございました。