最近よく見るようになった、奥行感を演出するスクロール。いわゆるパララックスと呼ばれる演出効果。もちろんこれもJavaScriptを使って実装されています。

サンプルを見る

奥行を理解する。

パララックスを理解するには、2D空間における奥行感を理解する必要があります。 下の図を見てください。

これが奥行感を演出する際の鉄則です。 皆さんも、空を眺めたとき、飛行機がゆっくり空を飛んでいるのを見たことがあるはずです。 でも、普通に考えて、飛行機があんなにゆっくり飛んでるはずはありません。

そう、遠くにあるものはゆっくり動いて見えるのです。 そのあたりの理屈は、遠近法と同じですね。同じ10メートルでも、目の前の10メートルと1キロ先の10メートルでは視認できる大きさが違います。

もう一つ例を挙げると、空を浮かぶ雲を見たときに、速い雲と遅い雲があるはずです。 雲は風に乗って動くため、速度の違いなんてあるはずがありません。それはつまり、遅い雲は、早い雲よりももっと遠くにあるからなのです。

さて、そこまでの理屈を理解したところで、JavaScriptでの実装に入りたいと思います。

スクロール量を取得する。

スクロールにおいて、速度という概念はありません。 何ピクセル上にスクロールするか?というだけです。

それを速度に置き換えるには、一回の処理な何ピクセル動くか? ということになります。

そこで利用できる値に、「scrollTop」という値があります。jQueryを使えば簡単に取得できるのですが、これは、画面をスクロールした際に「一体何ピクセルスクロールしているか」というスクロール位置になります。

また、スクロール自体をイベントとして取得することもできます。

それらをまとめた処理が、サンプルソース中の、こちらになります。

<script type="text/javascript">
$(function()
{
    $(window).bind("scroll" , function(e)
    {
        var scrollTop = $(window).scrollTop();
        $("#info").text(scrollTop);
    });
});
</script>

この様に、「window」に対して「scroll」イベントをバインドします。 すると、画面全体のホイールスクロール・スクロールバーによるスクロールを取得できます。

そして、$(window).scrollTop();の記述により、現在のスクロール位置が取得できます。 値は正の整数で帰ってきます。

サンプルの左上に表示されている数値がそれです。

この値は、「0の位置から、何ピクセルスクロールしているか?」という値になります。 では、次にこの値をどう使うのか解説しましょう。

postion:fixedを利用する。

scrollTopの値の使い方を説明する前に、重要事項として、画面のスクロールに依存しない要素を用意しなくてはいけません。

そこで一番簡単なのが、CSSの「postion:fixed」を使う手です。 ただし、IE6はこのプロパティに対応していないので、こういった古いブラウザに対応するためには、「position:absolute」と「display:scroll」を使うなどして、なんとか工夫するしかありません。

ただ、出来れば「position:fixed」を使うのが簡単なので、できればIE6は代替コンテンツで逃れるのがいいですね。

さて、「postion:fixed」を設定し、「absolute」と同様、位置指定してスクロールすると、「fixed」が指定された要素は、スクロールせず、指定した位置に留まります。

つまり、「fixed」を指定した要素はスクロールから独立して配置されることになります。 そしたら次は、配置した要素を、スクロール速度よりも遅い速度で移動するようにすればいいのです。

上方向に移動するには、「top」の値を減らせばいいので、scrollTopの値を、最初に配置されている座標から引けば、通常のスクロールと同じように動きます。

しかしそれでは通常のスクロールと同じなので、ここで一工夫。

スクロールの速度を決めるのは、一回の処理で何ピクセル動くかです。 なので、一回の処理で、scrollTopの値より多く動けば、全体のスクロール、つまり奥の要素よりも速く動くということになります。

<script type="text/javascript">
var float1Top = 400;
var float2Top = 600;
$(function()
{
    $(window).bind("scroll" , function(e)
    {
        var scrollTop = $(window).scrollTop();
        $("#info").text(scrollTop);
        $("#float1").css("top" , float1Top - (scrollTop * 1.2) + "px");
        $("#float2").css("top" , float2Top - (scrollTop * 1.4) + "px");
    });
});
</script>

上記コードを解説すると、
var float1Top = 400;
ここで、予めそれぞれの要素を取得し、
var scrollTop = $(window).scrollTop();
$("#float1").css("top" , float1Top - (scrollTop * 1.2) + "px");
「scrollイベント」のハンドラ内で、それぞれの要素の初期位置を基準に、現在のscrollTopよりも大きい数を引いてやります。

そうすると、上記の式だと、例えばscrollTopが100の時は「400-120」、200の時は「400-240」といったように、scrollTopの位置によって、scrollTopの移動量よりも大きく、尚且つ、scrollTopがどんな値でも変動しない値を取得することができます。

この、「変動しない」というのが重要で、こういったインタラクティブなコンテンツを作るときは、計算をややこしくしてしまうと、scrollTopの位置が一緒でも、条件によっては値が変わってしまうこともあり、バグの隠れた原因になります。

しかし、この書き方だと、移動する要素がどこにいても、必ず最初に設定した基準の位置で計算し、ウインドウの高さがいくつであっても、必ず同じ値になります。

如何でしょうか? 今回のサンプルを応用すれば、結構大きめのパララックスのコンテンツを作れちゃうかもしれませんね。

河野 義貴
インハウスのFlashクリエイターとして勤務後、2010年独立。一年間のフリーランス期間を経て、2011年9月にスウィーツアンドストリーム株式会社を設立。主にFlash・HTML5を駆使した、PC・スマートフォン向けインタラクティブコンテンツを中心に活動中。