このページの本文へ

スクロールアニメーションによる立体コンテンツの見せ方

2014年07月22日 11時00分更新

本間宣光 / Stronghold

  • この記事をはてなブックマークに追加
本文印刷

STEP 3:スクロール値でアニメーションさせる

 スクロール値の取得と、奥行きのあるコンテンツの作成ができたので、いよいよアニメーションをさせてみよう。

 今回のデモでは、1画面の高さをheight: 100%; とし、スクロール値が#sectionの半分に達したときに「.card」のrotateXが0になるようにする。具体的には、以下の計算式で求めた値を変数rotateXに代入する。

 変数rotateXの値をtransformプロパティのrotateX関数の引数に渡すことで、スクロール量に応じたコンテンツの変形が実現する。なお、rotateXの値がマイナス値になると「.card」が逆向きに変形してしまうため、値が0を下回ると0を代入して変形を止めている。

■ソースコード(HTML)

<div id="wrapper">
     <div id="section" class="inner red">
        <div id="content" class="perspective">
            <div class="card">
                <span>CONTENT</span>
            </div>
        </div>
    </div>
    <div id="footer"></div>
 </div>

■ソースコード(CSS)

{
    margin: 0;
    padding: 0;
    border: 0;
    outline: none;
    -webkit-box-sizing: border-box;
       -moz-box-sizing: border-box;
        -ms-box-sizing: border-box;
         -o-box-sizing: border-box;
            box-sizing: border-box;
}
html, body {
    width: 100%;
    height: 100%;
}
#wrapper,
.inner {
    position: relative;
    width: 100%;
    height: 100%;
}
.perspective {
    -webkit-perspective: 1000px;
       -moz-perspective: 1000px;
           -ms-perspective: 1000px;
         -o-perspective: 1000px;
            perspective: 1000px;
    -webkit-transform-style: preserve-3d;
       -moz-transform-style: preserve-3d;
        -ms-transform-style: preserve-3d;
         -o-transform-style: preserve-3d;
            transform-style: preserve-3d;
}
.card {
    position: relative;
    display: block;
    margin: 0 auto;
    width: 100%;
    height: 100%;
    border: 10px solid #FFF;
    -webkit-transform-origin: 50% 100%;
       -moz-transform-origin: 50% 100%;
        -ms-transform-origin: 50% 100%;
         -o-transform-origin: 50% 100%;
            transform-origin: 50% 100%;
    -webkit-transform: rotateX(90deg);
       -moz-transform: rotateX(90deg);
        -ms-transform: rotateX(90deg);
         -o-transform: rotateX(90deg);
            transform: rotateX(90deg);
}
.card span {
    display: block;
    position: absolute;
    top: 50%;
    margin-top: -50px;
    width: 100%;
    height: 100px;
    color: #FFF;
    font-size: 80px;
    text-align: center;
    text-transform: uppercase;
    line-height: 100px;
}
.red { background: #F4726D}
.red .card { background: #F68985}
#content {
    position: absolute;
    bottom: 0;
    width: 100%;
    height: 50%;
}
#footer {
    position: relative;
    width: 100%;
    height: 50%;
    background: #F68985;
}

■ソースコード(JavaScript)

$(function() {
    // ウィンドウの高さを取得
    var winH = $(window).height();
    // ウィンドウの半分の高さを取得
    var winHalfH = winH / 2;
    // セクショントップのY座標を取得
    var secT = $('#section').offset().top;
    $(window).on('scroll'function() {
        // 現在のスクロール位置
        var scrollPos = $(this).scrollTop();
        // #section の半分までスクロールしたら rotate(0deg) にする
        var rotateX = 90 - ((scrollPos - secT) * (1 / (winHalfH / 90)));
        // 角度がマイナスになったら 0 に固定する
        if (rotateX <= 0) {
            rotateX = 0;
        }
        // rotate の値を代入しアニメーションさせる
        $('#content > .card').css({
            'transform''rotateX(' + rotateX + 'deg)'
        });
    });
});

STEP 4:複数のコンテンツをアニメーションさせる

 最後に、STEP 3で完成したアニメーションを、参考サイトのように複数のコンテンツに対応させよう。

 基本はSTEP 3で作った動きを繰り返すだけだが、複数のコンテンツにアニメーションを適用する場合は、どのセクション間をスクロールしているかを知る必要がある。そこで、if文を使って各セクションのY座標とスクロール値からセクションの位置を判断し、それぞれのセクションのアニメーションを展開する。

■ソースコード(HTML)

<div id="wrapper">

    <div id="section-1" class="inner red">
        <div id="content-1" class="perspective">
            <div class="card">
                <span>CONTENT 1</span>
            </div>
        </div>
    </div>

    <div id="section-2" class="inner blue">
        <div id="content-2" class="perspective">
            <div class="card">
                <span>CONTENT 2</span>
            </div>
        </div>
    </div>

    <div id="section-3" class="inner yellow">
        <div id="content-3" class="perspective">
            <div class="card">
                <span>CONTENT 3</span>
            </div>
        </div>
    </div>

    <div id="section-4" class="inner green">
        <div id="content-4" class="perspective">
            <div class="card">
                <span>CONTENT 4</span>
            </div>
        </div>
    </div>

    <div id="footer">
        <a href="#section-1" class="top">Scroll to Top</a>
    </div>

</div>

■ソースコード(CSS)

{
    margin: 0;
    padding: 0;
    border: 0;
    outline: none;
    -webkit-box-sizing: border-box;
       -moz-box-sizing: border-box;
        -ms-box-sizing: border-box;
         -o-box-sizing: border-box;
            box-sizing: border-box;
}
html, body {
    width: 100%;
    height: 100%;
}
#wrapper,
.inner {
    position: relative;
    width: 100%;
    height: 100%;
}
.perspective {
    -webkit-perspective: 1000px;
       -moz-perspective: 1000px;
           -ms-perspective: 1000px;
         -o-perspective: 1000px;
            perspective: 1000px;
    -webkit-transform-style: preserve-3d;
       -moz-transform-style: preserve-3d;
        -ms-transform-style: preserve-3d;
         -o-transform-style: preserve-3d;
            transform-style: preserve-3d;
}
.card {
    position: relative;
    display: block;
    margin: 0 auto;
    width: 100%;
    height: 100%;
    border: 10px solid #FFF;
    -webkit-transform-origin: 50% 100%;
       -moz-transform-origin: 50% 100%;
        -ms-transform-origin: 50% 100%;
         -o-transform-origin: 50% 100%;
            transform-origin: 50% 100%;
    -webkit-transform: rotateX(90deg);
       -moz-transform: rotateX(90deg);
        -ms-transform: rotateX(90deg);
         -o-transform: rotateX(90deg);
            transform: rotateX(90deg);
}
.card span {
    display: block;
    position: absolute;
    top: 50%;
    margin-top: -50px;
    width: 100%;
    height: 100px;
    color: #FFF;
    font-size: 80px;
    text-align: center;
    text-transform: uppercase;
    line-height: 100px;
}
.red { background: #F4726D}
.blue { background: #5CA9D6}
.green { background: #6CC88A}
.yellow { background: #FCD04B}
.red .card { background: #F68985}
.blue .card { background: #70B4DB}
.green .card { background: #7FCF99}
.yellow .card { background: #FCD764}
#content-1,
#content-2,
#content-3,
#content-4 {
    position: absolute;
    bottom: 0;
    width: 100%;
    height: 50%;
}
#footer {
    position: relative;
    width: 100%;
    height: 50%;
    background: #EEE;
}
a.top {
    display: block;
    position: absolute;
    top: 50%left: 50%;
    margin-top: -35px;
    margin-left: -150px;
    width: 280px;
    height: 60px;
    color: #888;
    font-size: 20px;
    text-align: center;
    line-height: 52px;
    text-transform: uppercase;
    border: 4px solid #888;
    text-decoration: none;
}

■ソースコード(JavaScript)

$(function() {

    // ウィンドウの高さを取得
    var winH = $(window).height();
    var winHalfH = winH / 2;

    // 各セクショントップのY座標を取得
    var sec1T = $('#section-1').offset().top;
    var sec2T = $('#section-2').offset().top;
    var sec3T = $('#section-3').offset().top;
    var sec4T = $('#section-4').offset().top;
    var footerT = $('#footer').offset().top;

    $(window).on('scroll'function() {

        // 現在のスクロール位置
        var scrollPos = $(this).scrollTop();

        // section-1 から section-2 の間をスクロールしている時
        if ( (scrollPos >= sec1T) && (scrollPos < sec2T) ) {

            // section-1 の画面半分までスクロールしたら rotate(0deg) にする
            var rotateX = 90 - ( (scrollPos - sec1T) * (1 / (winHalfH / 90)) );
            // 角度がマイナスになったら 0 に固定する
            if (rotateX <= 0) { rotateX = 0; }
            // rotate の値を代入しアニメーションさせる
            $('#content-1 > .card').css({'transform''rotateX(' + rotateX + 'deg)' });
            // 次の section の rotate をリセット
            $('#content-2 > .card').css({'transform''rotateX(90deg)' });

        }
        // section-2 から section-3 の間をスクロールしている時
        else if ( (scrollPos >= sec2T) && (scrollPos < sec3T) ) {
            var rotateX = 90 - ((scrollPos - sec2T) * (1 / (winHalfH / 90) ));
            if (rotateX <= 0) { rotateX = 0; }
            $('#content-2 > .card').css({'transform''rotateX(' + rotateX + 'deg)' });
            $('#content-3 > .card').css({'transform''rotateX(90deg)' });

        }
        // section-3 から section-4 の間をスクロールしている時
        else if ( (scrollPos >= sec3T) && (scrollPos < sec4T) ) {
            var rotateX = 90 -  ((scrollPos - sec3T) * (1 / (winHalfH / 90) ));
            if (rotateX <= 0) { rotateX = 0; }
            $('#content-3 > .card').css({'transform''rotateX(' + rotateX + 'deg)' });
            $('#content-4 > .card').css({'transform''rotateX(90deg)' });
        }
        // section-4 から footer の間をスクロールしている時
        else if ( (scrollPos >= sec4T) && (scrollPos < footerT) ) {
            var rotateX = 90 -  ((scrollPos - sec4T) * (1 / (winHalfH / 90) ));
            if (rotateX <= 0) { rotateX = 0; }
            $('#content-4 > .card').css({'transform''rotateX(' + rotateX + 'deg)' });
        }

    });

});

バリエーション&アレンジのヒント

 今回はスクロールと回転 (rotateX) を組み合わせたが、スクロール値をもとにしたアニメーションは、数値を扱うすべてのCSSプロパティに応用できる。

 以下の例では、transformのほかにopacityプロパティやSVGのstroke-dashoffsetプロパティなどを組み合わせている。いろいろ組み合わせてみるとおもしろいだろう。

DEMO > http://zxcvbnmnbvcxz.com/demonstration/as/006/5.html

著者:本間宣光(ほんま・のぶあき)

著者写真

1990年生まれ。株式会社レターズのデザイナー。2014年からWebデザイナーとして働き始める。Webに関する活動拠点「Stronghold」というサイトでブログを書いたり、デザインの実験をしている。

Web Professionalトップへ

この連載の記事

一覧へ
Web Professionalトップページバナー

この記事の編集者は以下の記事をオススメしています

ASCII.jp会員サービス 週刊Web Professional登録

Webディレクター江口明日香が行く