[jQuery] カーソルの動きに合わせて動くパララックスを作る方法
jQueryのmousemoveイベントの事を勉強したので、このイベントを使ってカーソルの動きに合わせて画像を動かし、パララックス効果を出すサンプルを作ってみました。備忘録も兼ねてその流れをまとめました。
このコードをプラグイン化してみました!→[jQuery] 画像や背景画像をグルグルできる jQuery.Simple3D プラグインを作りました
参考にさせて頂いたプラグイン
いろいろコードを覗いてみましたが、jQuery.Smart3D のコードが私にはわかりやすかったので計算式などだいぶ参考にさせて頂きました。
mousemoveイベントについて
mousemoveイベントはマウスが要素上を動いた時に発生し、mousemoveイベントの引数からイベントに関するさまざまな情報を受取ることができます。マウスカーソルの位置もここで取得することができます。
作ったサンプルデモ
Simple3Dmove_Sample|memocarilog-demo

作ったサンプルは以下のアドレスからダウンロードできます。
カーソルの動きに合わせて動くパララックスを作るコード
HTMLのコード
HTMLは下のようにul要素で囲い、画像をli要素でマークアップします。
<ul id="sample"> <li><img src="images/kusa1.png" alt="くさ"></li> <li><img src="images/hana.png" alt="はな"></li> <li><img src="images/kusa2.png" alt="くさ"></li> <li><img src="images/syabondama.png" alt="シャボン玉"></li> </ul>
あとでCSSで画像を position: absolute で全部重ねあわせますが、下の方に配置した画像が上に重なることになるので並べ順に注意です。
CSSのコード
まず、親要素となる #sample へ position:relative を指定し、子要素の li へ position: absolute を指定します。width と height は子要素の li の方を若干親要素より大きいサイズに指定します。
#sample {
/* jQueryに必要な指定 */
position: relative;
overflow: hidden;
margin:0 auto 50px ;
width: 700px;
height: 450px;
/* 背景とフレームの指定 */
outline: solid 2px #ddd;
border: solid 20px #fff;
background: url(images/bg.jpg);
box-shadow: 1px 1px 50px RGBA(0,0,0, .2) inset ;
}
#sample li{
position: absolute;
top:-25px;
left: -50px;
width: 800px;
height: 500px;
}
#sample li の top値 と left値 は ul要素とli要素を中央で揃える為に指定しています。(計算式→ ul縦幅 – li縦幅)÷ 2 = top値 / ul横幅 – li横幅)÷ 2 = left値)
次に、各画像のCSS指定をします。各画像の表示位置を指定するため、ここでも position: absolute にし適当な位置を指定します。
/* くさ1 */
#sample li:nth-child(1) img{
position: absolute;
bottom:0;
}
/* はな */
#sample li:nth-child(2) img{
position: absolute;
bottom:50px;
}
/* くさ2 */
#sample li:nth-child(3) img{
position: absolute;
bottom: -30px;
}
/* シャボン玉 */
#sample li:nth-child(4) img{
position: absolute;
bottom: 150px;
opacity: 0.4;
}
jQueryのコード
jQuery本体を読み込み、4行目の「$(‘#sample’)」の部分に親要素のIDを指定します。
<script src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
<script>
$(function(){
var thisObj = $('#sample');
// 親ボックスのオブジェクトを作る
if (thisObj.length == 0) return false;
// thisObj に何も入っていなければ false を返す
var item = thisObj[0];
// 親ボックスオブジェクトから構造の情報を取り出す(ul liなどの構造)
以下のように各要素の縦橫のサイズなどを取得します。
var liWidth = $('>li', item).width()
// li要素の横幅を取得
var liHeight = $('>li', item).height()
// li要素の縦サイズを取得
var ulWidth = thisObj.width();
// 親要素の横幅取得
var ulHeight = thisObj.height();
// 親要素の縦サイズを取得
var offset_x = liWidth - ulWidth;
// ↑ liから親ボックスの横の大きさをひいた数
var offset_y = liHeight - ulHeight;
// ↑ liから親ボックスの縦の大きさをひいた数
var itemLi = thisObj.find('li');
// thisObjからli要素を取り出す
次にmousemoveイベントで取得できるカーソルの位置を使って、画像が動ける範囲などを計算します。
thisObj.mousemove(function(e){
// ↑「e」に現在のカーソル位置の情報などが入る。
// x方向の計算 ========
var cursorX = e.clientX - thisObj.offset().left;
// e.clientY → 表示画面上からの距離
// thisObj.offset().top → ドキュメント左からの距離
// cursorX → 親ボックス左からみたカーソルの相対位置
(cursorX > ulWidth) ? cursorX = ulWidth : cursorX ;
// 親ボックスからみたカーソルの位置が横幅より大きくなった場合は ulwidth値を入れる
var centerX = (cursorX / ulWidth * offset_x) - offset_x / 2 ;
// X方向中心からみたカーソル位置の計算(中心を0とする)
// y方向の計算 ========
var cursorY = e.clientY - thisObj.offset().top + $('html').scrollTop();
// e.clientY → 表示画面上からの距離
// thisObj.offset().top → ドキュメントから上の距離
// cursorY → 親ボックス上からみたカーソルの相対位置
(cursorY > ulHeight) ? cursorY = ulHeight : cursorY ;
// 親ボックスからみたカーソルの位置が縦幅より大きくなった場合は ulHeight値を入れる
var centerY = (cursorY / ulHeight * offset_y) - offset_y / 2;
// Y方向中心からみたカーソルの位置の計算(中心を0とする)
つづいてli要素を移動させる処理をします。カーソルの移動値から計算した値を新しい移動先として、CSSのleft値とtop値をちくいち変更します。カーソルが動くごとにちくいち計算し移動先値も変わっていく為スムーズに画像が動いているように見えます。
// li要素を移動させるループ ========
for (var i=1; i<= itemLi.length; i++){
// x方向の移動処理
var liLeft = parseFloat($(itemLi[i-1]).css('left'));
// liのleft値を取得.parseFloat → 文字列を数値に変換する
var newLeft = centerX * (i / itemLi.length) - offset_x / 2;
// liの個数分だけそれぞれ違うnewLeft値を計算する
$(itemLi[i-1]).css('left', (newLeft + liLeft*5) / 6);
// それぞれのliのCSS'left'値を変更する。/6 の数値を大きくすると動きも小さく
// Y方向の移動処理
var liTop = parseFloat($(itemLi[i-1]).css('top'));
// liのtop値を取得.parseFloat → 文字列を数値に変換する
var newTop = centerY * (i / itemLi.length) - offset_y / 2;
// liの個数分だけそれぞれ違うnewTop値を計算する
$(itemLi[i-1]).css('top', (newTop + liTop*5) / 6);
// それぞれのliのCSS'top'値を変更する。/6 の数値を大きくすると動きも小さく
} // li要素を移動させる処理ここまで
});
});
</script>
この計算式では自動的にliごとに違った移動値を出し、liそれぞれ移動先が変わることで奥行きがある感じを出しています。掛ける数や割る数を変えるとまた違った動きにもなります。
コメントを沢山書いたので長いコードに見えますが、実際はそんなに長くないです。サンプルの項目からダウンロードできるファイルでコメントのない、一連のコードが見れます。親要素を指定するだけで簡単に3Dっぽい動きが作れます。
丁寧なコメントで良く理解することができました!
おお!ナカムラさん(^o^)拙コードですが見て下りありがとうございます…!