画像などをマウスオーバーするとマウスが侵入した方向からオーバーレイを出すというテクニックがあります。
変化をつけたい時などは有効ですが、モバイルからのアクセスが多くなった昨今、タッチデバイスでは表現できない(する必要がない)ので、あまり使われなくなったテクニックをあえて紹介します。
実際の出来上がりサンプルは下記になります。
順番に説明します。
方向の計算ロジックはDirection-Aware Hover Effect with CSS3 and jQueryを参考にしました。
手順1:完成形をつくる
他の事でも同じですが、特にアニメーションをさせたい場合はスタート時点から作るのではなく、最終の状態から作成していくことをおすすめします。
ここで重要なのは、親要素(ここでは.elem)にwidthとheightを設定し、overflow:hiddenで枠外は表示させないようにすることです。
これを怠ると破綻してしまいます。
オーバーレイは当然ですがabsoluteで親要素の上に被るようにしましょう。
手順2:初期状態を作る
完成形ができたら、追随させる要素(.elem-overlay)を枠外に出します。
top:100%でも、left:100%でもなんでもいいです。
とにかく出しましょう。
手順3:進入方向の取得
準備ができたらJavaScriptでイベントを作成します。
サンプルではjQueryを使って解説します。
まずは進入方向を取得します。
進入方向を計算するためにはマウスのx座標とy座標、要素の横と縦から角度を計算します。
基準となる要素自体の幅を取得
これがないと始まりませんので、要素の幅を取得します。
var w = $(elem).width();
var h = $(elem).height();
基準となる座標を取得
マウス座標に要素の座標と要素幅の半分を引き、長方形の場合はその比率を掛けます。
var x = (e.pageX - $(elem).offset().left - (w / 2)) * (w > h ? (h / w) : 1);
var y = (e.pageX - $(elem).offset().top - (h / 2)) * (h > w ? (w / h) : 1);
角度を割り出し方向を決定する
アークタンジェントを利用し、要素内におけるマウス座標のベクトル角度を取得します。
アークタンジェントに関してはdA-toolsのサイトが参考になります。
var deg = Math.atan2(y, x) * 180 / Math.PI
※ここでyとxを反対にするとベクトル角度も変わってしまうのでその後の計算も変更する必要があります。
計算した角度を反転(180度を足す)し、さらに90度で割ります。
var deg2 = (deg + 180) / 90;
算出された角度を4で割った余りで方向を決定します。
var direction = deg2 % 4;
角度を計算する際に四捨五入をして整数にしておくことも必要なので最終的には下記のようになります。
var direction = Math.round((((Math.atan2(y, x) * 180 / Math.PI) + 180) / 90)) % 4;
これで、0〜3の間が取得できるようになりました。
0 = 左
1 = 上
2 = 右
3 = 下
ここまでくれば9割完成です。
導き出した方向にtop/left値を設定する
マウスオーバー状態時のオーバーレイ方向は下記のように動くよう設定する必要があります。
- 左方向 = left: -(要素の横幅) → 0 , top: 0
- 右方向 = left: 0 → 要素の横幅 , top: 0
- 上方向 = left: 0 , top: -(要素の縦幅) → 0
- 下方向 = left: 0 , top; 要素の縦幅 → 0
マウスが外れる場合は下記のように設定します。
- 左方向 = left: 0 → -(要素の横幅) , top: 0
- 右方向 = left: 要素の横幅 → 0 , top: 0
- 上方向 = left: 0 , top: 0 → -(要素の縦幅)
- 下方向 = left: 0 , top; 0 → 要素の縦幅
これらを簡単に書くと下記のように指定ができます。
let w = $(elem).width();
let h = $(elem).height();
let $styles = {
top: 0,
left: 0
};
switch (direction) {
case 0: // 左
$styles.left = -w;
break;
case 1: // 上
$styles.top = -h;
break;
case 2: // 右
$styles.left = w;
break;
case 3: // 下
$styles.top = h;
break;
default:
return false;
}
let pre = {top:0,left:0};
let end = {top:0,left:0};
if(e.type === 'mouseenter'){
pre.top = $styles.top;
pre.left = $styles.left;
}else{
end.top = $styles.top;
end.left = $styles.left;
}
あとは、アニメーションさせる前にCSSをセットしてからアニメーションさせれば完了です。