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プロパティなどを組み合わせている。いろいろ組み合わせてみるとおもしろいだろう。
著者:本間宣光(ほんま・のぶあき)
1990年生まれ。株式会社レターズのデザイナー。2014年からWebデザイナーとして働き始める。Webに関する活動拠点「Stronghold」というサイトでブログを書いたり、デザインの実験をしている。