TL;DR
この記事で解説するパララックスはこんなの(CodePen)です。
まえがき
パララックス、素敵ですよね。
オサレなサイトに行くとたまに背景や要素に適用されていて、思わず「おっ」と見入ってしまいます。
僕もあるサイトの背景に当ててみようと思い立ち、偉大なる Google 先生にお尋ね申し上げましたが、検索結果にあったのは主に手前の要素を動かすパララックス(こちらはRellaxというライブラリがオススメです)で、背景のみをゆっくりスクロールさせる僕の求めていたパララックスはありませんでした。
そこで自分で作ってみたら意外と簡単だったので記事を書いてみた次第です。
background-attachment
?
背景画像をパララックスと聞いて最初に思いつくのはCSSのbackground-attachment
プロパティです。
これにfixed
という値を設定すると、要素をスクロールしても背景はスクロールせず、パララックスのようなものを演出できます。
意気揚々とこのコードを書いた僕を待っていたのは悲しき運命~~(さだめ)~~でした。
悲しみの画像
そうです。もはや僕達現代人の臓器になりつつあるスマホで、背景画像を要素いっぱいに表示するbackground-size: cover
と先述のbackground-attachment
はサポートされていないのです。
そんな悲しみにくれていた僕に話しかけたのはある一つのMDNの記事でした。
object-fit
!
彼は、object-fit
プロパティと我らが<img>
要素でbackground-size: cover
と同じようなことができるよ、というのです。
あとは、background-attachment
ですが、これはJavaScript
でなんとかするとしましょう。
viewport(ドキュメントの表示領域)の上端からの距離を取得してtransform
でその分移動させています。
top
にしなかったのはパフォーマンスを考えてです。
そうしてできたのがこちらです。しかし結構がくつきます……。
requestAnimationFrame
!
困り果てた僕は先ほどちょろっと話したRellaxのソースコードを呼んでみました。するとソースのどこにもaddEventListener
やonscroll
(これは論外ですね)の文字はありませんでした。
どうやら requestAnimationFrame
というものを使ってるようです。調べてみたところ、これはマシンの性能やタブの状態(バックグラウンドかフォアグラウンドかといったもの)によりFPSが変わるsetTimeout
のようなものだそう。
特にFPSは関係ない今回のようなケースにはぴったりですね!
以上を踏まえてできたコードがこちらです。
ゆっくり動かす
さて、ここまでCSSでできることをわざわざJavaScriptでやってきたのはスマホに対応させる以外にも理由があります。
それは、CSSのみだったら背景画像を固定することはできてもゆっくり動かすことはできません。
しかし、JavaScriptならできます。
分かりやすく図をかいてみると以下のようになります。
確かにゆっくり動いているように見えます。
☆の部分は、要素が画面に見え始めた時点で0、見え終わった時点ではみ出した部分の全体となります。
つまり、(viewportの高さ - 要素のviewport上端からの距離) / (画面の高さ + 要素の高さ)
が移動する割合になるので、背景画像のviewportからはみ出た部分にかけて、(viewportの高さ - 要素のviewport上端からの距離) / (画面の高さ + 要素の高さ) * (背景画像の高さ - viewportの高さ)
となります。
それをコードにしたのがこれというわけですね。
あとがき
式を立てるのが難しかったです……。
ほかは結構簡単でした。
Macやスマホで少々がたついちゃうのですがしょうがないんでしょうか……。