前回、Vanilla-tilt.jsを紹介しました。
このライブラリの使用方法は、下記の記事にて紹介しています。
これがなかなかマウス操作が面白くて気に入ってしまい、3D立方体をマウス操作で回転させてみることにしました。
Vanilla-tilt.jsのおかげでとても簡単に実装できました。
初期状態からマウスをのせた箇所が手前に来るように回転
CODEPEN
「Run Pen」をクリックしてください。
立方体の上にマウスをのせてゆっくり移動させてみてください。
See the Pen tilt_cube by blue moon (@blue-moon) on CodePen.
もし気に入ってもらえたなら、先に紹介した記事を参考にVanilla-tilt.jsを使用してみてください。
とても簡単なのでおすすめです。
HTMLファイル
<body>
<!-- 最大回転角度は180度、マウスから離れた時の回転角度を維持、速度は1秒、ページ表示時の回転角度は各30度 -->
<div class="cube" data-tilt data-tilt-max="180" data-tilt-reset="false" data-tilt-speed="1000" data-tilt-startX="-30" data-tilt-startY="30">
<div class="surface front"><a href="">front</a></div>
<div class="surface right"><a href="">right</a></div>
<div class="surface back"><a href="">back</a></div>
<div class="surface left"><a href="">left</a></div>
<div class="surface top"><a href="">top</a></div>
<div class="surface bottom"><a href="">bottom</a></div>
</div>
<!-- jQueryはなくてもOK! vanilla-tilt.jsをCDNで読み込み-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/vanilla-tilt/1.7.2/vanilla-tilt.min.js"></script>
</body>
tiltの対象とする要素
立方体を構成する面の親要素(クラスcube)にのみ、tiltのオプションを追加しています。それだけで十分です。
くれぐれも子要素の立方体の面は、tiltの対象としないよう気を付けてください。
というのは、各面は後述するCSSでも確認できますが、transformプロパティで回転させています。
もし、tiltの対象とすると、このCSSのプロパティの値が初期化されてしまいます。
初期状態とマウスが離れた時の角度
デフォルトでは、最初の表示時の回転角度は0度であるため、読み込み時に回転角度を指定しています。
たとえ、CSSの方で回転角度を設定していたとしても、Vanilla-tilt.jsによって上書きされてしまい、回転角度は初期状態の0度となってしまいます。
つまり、立方体の前面のみが平面のように見えるだけとなってしまい、ユーザーは3D立方体であるとこを認知できません。
そのため、tiltのオプションの方で、初期の回転角度を指定しておいた方がよいと思います。
また、デフォルトでは、マウスが離れた時に回転角度はリセット、つまり先ほどと同じように、立方体の前面のみしか見えない状態となります。
そのため、マウスから離した時、最後の角度からリセットしない設定をしています。
最大角度
回転角度の最大値は360度が適切と考えてしまうかもしれませんが、180度で充分だと思います (-180度~180度の間、つまりトータルで360度回転可能となるので)。
もちろん、180度(-180度)回転した時点で止まることになりますが、逆回転すれば足りるので問題ないと思います。
それ以上に許容回転角度を大きくすると、マウスの動きに過剰に回転しすぎてしまい、かえって扱いづらくなってしまいます。
CSSファイル
* {
box-sizing: border-box;
background: #000c30;
}
body {
-webkit-box-reflect: below 0px linear-gradient(rgba(255, 255, 255, 0) 0%, rgba(255,255,255,0.2) 50%, rgba(255,255,255,0.35) 100%); /* 鏡面反射 */
min-height: 140px;
}
.cube {
margin: 50px auto; /* 3D回転するため、余裕をとって置いておいた方がよい */
width: 100px; /* 各面の大きさ */
height: 100px;
transform-style: preserve-3d; /* 子要素(面)を3D空間に配置、Z軸移動が可能となる */
background: rgba(255, 255, 255, 0); /* 各面は色を付けているが、親要素自体は色ベース色のまま、中心に残って見えてしまうため。 */
}
.surface {
position: absolute; /* 必須、面は全て同じ位置にある状態、ここを起点に各面を回転 */
width: 100px; /* 親要素と同じ */
height: 100px;
display: flex;
align-items: center;
justify-content: center;
box-shadow: inset -4px -4px 10px rgba(240,240,240,0.9), /* 外側の影は平面のままで不自然 */
inset 4px 4px 10px rgba(240,240,240,0.9); /* 内側にのみ白っぽい影 */
}
a {
padding: 0.3em; /* 回転によりテキスト等はマウスでとらえるのが難しくなるため、範囲を大き目に */
display: inline-block;
background: #888; /* テキストで切り抜く色(ほぼ黒) */
-webkit-background-clip: text;
background-clip: text; /* 背景色#888(ほぼ黒に近い)をテキストで切り抜き */
color: transparent; /* テキストの色は透明にしておく */
font-weight: 700;
text-shadow: 1px 1px 1px #fff; /* 切り抜いた後、影を付け立体的に */
letter-spacing: 0.1em;
text-decoration: none;
}
a:hover {
background: #c71585;
-webkit-background-clip: text; /* これはもとの要素(aタグ)と重複するが、省略するとテキスト切り抜きが継承できない */
background-clip: text;
text-shadow: 0.7px 0.7px 0.7px rgba(255,255,255,0.5), 0 0 10px #ff1cac, 0 0 18px #ffb3e3; /* ピンク系のシャドウを2つ重ね */
}
/*
以降は、各面(同じ位置にある)の3D空間上の回転を設定
それぞれZ軸に同じ距離手前に移動している
回転軸の起点(transform-origin)の設定は不要、全て起点は中心
*/
.front {
/* transform: translateZ(50px) rotateY(30deg); tiltで初期化されるため、rotateY(30deg)は不要 */
transform: translateZ(50px); /* 正面の部分、Z軸方向への移動を忘れずに */
}
.right {
transform: rotateY(90deg) translateZ(50px);
}
.back {
transform: rotateY(180deg) translateZ(50px);
}
.left {
transform: rotateY(-90deg) translateZ(50px);
}
.top {
transform: rotateX(90deg) translateZ(50px);
}
.bottom {
transform: rotateX(-90deg) translateZ(50px);
}
断念した点
もし、背景色が明るい白系統であれば背面に立方体の影をつけたり、今回のように暗い色であれば発光しているような明るい色の周囲につけようと考えました。
しかし、影は動く立方体全体を囲む形状にはならなかったのです。
立方体の、ある一つの面が真正面に来た時に、その面に隣接している面の影が線のように見えてしまいます。
各面に影をつけてもダメなら、親要素(立方体自体)につけてみたり、親要素の疑似要素を作ってみたり、親要素の兄弟要素を作って重ね合わせてみたり、filter: drop-shadow()にしてみたり…でもダメでした。
立方体の下方に(背面でなく)、ぼんやりと丸い影を作ることはできたかもしれませんが、立方体の動きと連動しないからなーとやっぱり止めときました。
鏡面反射
そこで、何か面白いことを付け加えてみようと思い、立方体の下方に鏡面反射させてみました。
これは、tiltのオプションではありません。
使用したCSSのプロパティは、-webkit-box-reflect
(MDN 英語ページへのリンク)です。
但し、このプロパティは標準化されたものではなく、将来にわたってサポートされるかも不明です。
やはり、このプロパティも3Dにはうまく対応してくれず(もしくは、transformプロパティと相性がよくないのか?)、立方体またはそれらの面に設定してもうまくいきません。
ということで、その親要素に(今回はbodyタグ)に設定してみました。