先日、某案件でスクロールして奥に進むというページを作成しました。
IEを無視すれば意外とさくっと作れるものなのだという事を知ったので、忘れないように記事にしたいと思います。
ちなみに、今回使用するCSSのperspectiveプロパティは、まだ草案段階のプロパティですので、
今後変更がある可能性もある事をご了承いただきたいです。
シームレスに奥に進むページ
サンプルはコチラです。
HTML
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
<body> <div class="base"> <div id="scaler" class="scaler"> <section class="section section-1" data-z="0"> <p class="text">コンテンツ</p> </section> <section class="section section-2" data-z="5"> <p class="text">コンテンツ</p> </section> <section class="section section-3" data-z="10"> <p class="text">コンテンツ</p> </section> <section class="section section-4" data-z="15"> <p class="text">コンテンツ</p> </section> <section class="section section-5" data-z="20"> <p class="text">コンテンツ</p> </section> </div> </div> <div id="scroll" class="scroll"></div> <script src="https://code.jquery.com/jquery-1.12.4.min.js"></script> <script type="text/javascript" src="sample_2.js"></script> </body> |
CSS
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
body { margin: 0; padding: 0; } .base { width: 1000px; height: 500px; margin: auto; border: 2px solid #000; position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); perspective: 1px; } .scaler { width: 100%; height: 100%; transform-style: preserve-3d; transform: translateZ(0); } .section { width: 100%; height: 100%; box-sizing: border-box; padding: 30px; background: #f00; position: absolute; top: 0; left: 0; } .section-1 { background: #f00; } .section-2 { background: #0f0; } .section-3 { background: #00f; } .section-4 { background: #ff0; } .section-5 { background: #0ff; } .scroll { visibility: hidden; z-index: -1; } |
JavaScript
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
// スクロール量を取得する要素を取得 var scrollElm = (function() { if('scrollingElement' in document) { return document.scrollingElement; } if(navigator.userAgent.indexOf('WebKit') != -1) { return document.body; } return document.documentElement; })(); // 全てのセクション要素を取得 var sections = document.querySelectorAll('.section'); // 全体をz方向に動かす#scaler要素を取得 var scaler = document.getElementById('scaler'); // 画面の高さを設定する#scroll要素を取得 var scrollDiv = document.getElementById('scroll'); // セクション要素のdata-z属性を取得し、transformを設定 // 最後のセクション要素のdata-zを元に、画面の高さを計算して設定 for(var i = 0; sections.length > i; i++) { var itemZ = sections[i].getAttribute('data-z'); sections[i].style.transform = 'translateZ(' + - itemZ + 'px)'; if(i === sections.length -1) { scrollDiv.style.height = itemZ * 100 + window.innerHeight + 'px'; } } // スクロールイベントで、#scaler要素のtransformでz軸を動かす window.addEventListener('scroll', function() { scaler.style.transform = 'translateZ(' + scrollElm.scrollTop / 100 + 'px)'; }); |
ざっくり解説
まずHTMLで、基盤となる親要素 .base を作り、
その中に、Z方向に動かす .scaler を作り、(英語は弱いので、クラス名は適当です。)
その中に、各セクション要素を並べます。
そして、このままではコンテンツの高さが無く、スクロールができないので、
コンテンツの高さを設定するための #scroll を最後に置きます。
この高さはJavaScriptで設定します。
各セクション要素に、そのセクションのZ方向の最初の位置を、独自のdata-z属性に設定しておきます。
CSSで、.baseを画面の中心に置き、fixedにします。
ポイントは、perspective: 1px; の所です。
これは、Z方向の奥行きを指定するプロパティのようですが、
1pxを指定する事で、基準の位置(最初の位置)から、手前に向かって画面から消え去るまでの距離が、1pxという事になります。
HTMLで作成したdata-z属性の値は、このperspectiveの値を基準にしていますので、
例えばdata-z=”5″であれば、基準の .base の位置から、5px奥に配置するという意味になっています。
後は、.scalerの transform: translateZ() の値を、スクロール値を元に変更していけば、奥に進むページが作れます。
(擬似的に)段階的に奥に進むページ
スルスルと奥に進んでいくのはシンプルで気持ちいいですが、若干素っ気ない気もします。
かと言ってスクロール動作をジャックするような事もやりたくありません。(個人的に嫌いですし、一般的にも嫌われているという認識です。)
では、スクロールイベントの処理を少し修正して、
.scalerのtranslateZ()の値を、5px単位で更新してみてはどうでしょうか。
1 2 3 4 5 6 |
window.addEventListener('scroll', function() { var scrollNum = Math.round(scrollElm.scrollTop / 100); if(scrollNum % 5 === 0) { scaler.style.transform = 'translateZ(' + scrollNum + 'px)'; } }); |
これで、.scalerのZ軸が5px単位で動くようになりました。
この状態で、CSSで.scalerにtransitionを追加すれば、良い感じになりそうです。
1 2 3 4 |
.scaler { /* 省略 */ transition: all .5s ease; } |
できました。サンプルはこちらです。
ナビゲーションをつける
こういうページの場合、ナビゲーションをつける場合が多いかもしれません。
これは実は難しくなく、普段使っているスムーススクロールのスクリプトを少し書き換えるだけで済みます。
animateの行き先(scrollTop)を、目的のセクションのdata-zの値を元に指定するだけです。
1 2 3 4 5 6 7 8 |
$('a[href^="#"]').on('click', function() { var speed = 300; var easing = 'swing'; $(scrollElm).animate({ scrollTop: $($(this).attr("href")).data('z') * 100 }, speed, easing); return false; }); |
サンプルはこちらです。
Z軸の角度を変える
CSSで、.baseにperspective-origin を追加すると、Z軸の基準点を変える事ができます。
試しに、perspective-origin: bottom; とすると、地を這うようにコンテンツが奥から現れます。
perspective-originの値は、数値の指定もできます。
perspective-origin: center bottom -150px; とすれば、少し下からコンテンツが現れるように見せることができます。
基本的にはこんな感じです。
各コードサンプルは、サンプルファイルからの抜粋ですので、
具体的なコードはサンプルファイルを参照してみてください。
perspectiveの値を変えてみたり、それに合わせてJSのスクロール値の計算方法を変えてみたりすれば、スクロール感は色々調節できるかと思います。
さらに、CSSを弄くったりスクロール値によってクラスを切り替えてtransrofmしたりすれば、色々と面白い演出ができそうです。