あいさつ

ハロー、yuki540だよ!ピロリン
↑ このテンションしんどいのでやめます
改めまして、yuki540です。
前回の記事読んでくれましたか?読んでない方は、ぜひ読んでみてください。
今回はキャラクターイラストを使ったアニメーション表現を紹介できたらなと思います。
で、今回作るのものはこちら。
(Twitterで「3時間目はこれにする!」って言ってたものがコロコロ変わってしまってすみません...)
WebGLっぽい立体表現を使った演出ですね。
perspective, transform-styleともに対応状況が良くなってきたので積極的に使っていい頃合いかなと思います。

(ただ今回作るもののような演出は、処理が重めなのであくまで「こういう演出もあるんだな〜」程度にみてください)
作ろう
まず、最終的に出来上がるものはこちらです。
はい。じゃあ一緒に作っていきましょう。
まず、時計から
まず、最初に↓の時計(?)から作っていきましょう。

↓マークアップはこんな感じになります。
<main class="stage">
<div class="stage__inner">
<section class="clock">
<div class="clock__frame">
<div></div><div></div><div></div><div></div>
<div></div><div></div><div></div><div></div>
<div></div><div></div><div></div><div></div>
<div></div><div></div><div></div><div></div>
<div></div><div></div><div></div><div></div>
<div></div><div></div><div></div><div></div>
</div>
<div class="clock__hands">
<div></div><div></div>
</div>
<div class="clock__image"></div>
</section>
</div>
<div class="stage__filter"></div>
</main>
先に.stage
にスタイルを適用してみましょう。
といってもサイズを画面全体にするだけです。単純ですね。
あと、.stage__filter
はbox-shadow
で内側に影をつけて、回想シーンのような雰囲気を表現しています。
* {
margin: 0;
padding: 0;
}
.stage {
position: absolute;
top: 0; left: 0;
width: 100%; height: 100%;
overflow: hidden;
}
.stage__inner,
.stage__filter {
position: absolute;
top: 0; left: 0;
width: 100%; height: 100%;
}
.stage__filter { box-shadow: 0 0 300px #444 inset; }
次に時計の縁(?)の部分にスタイルを適用してみましょう。
500px x 500px
の時計を画面の中心に配置しています。
そして、縁の部分の.clock__frame div
を24分割して、15deg
間隔を空けながら回転させています。(24個それぞれにスタイルをあてるのはsassなりを使うべきですね...)

.clock {
position: absolute;
top: calc(50% - 250px); left: calc(50% - 250px);
width: 500px; height: 500px;
background-color: rgba(100, 100, 100, 0.1);
border-radius: 50%;
}
.clock__frame {
position: absolute;
top: 20px; left: 20px;
width: calc(100% - 40px); height: calc(100% - 40px);
}
.clock__frame:before,
.clock__frame:after {
content: ""; display: block;
position: absolute;
top: 0; left: 0;
width: 100%; height: 100%;
border: solid 1px #444;
border-radius: 50%;
box-sizing: border-box;
}
.clock__frame:after {
top: 10px; left: 10px;
width: calc(100% - 20px); height: calc(100% - 20px);
}
.clock__frame div {
position: absolute;
top: 0; left: 0;
width: 100%; height: 100%;
}
.clock__frame div:after {
content: ""; display: block;
position: absolute;
top: 0; left: calc(50% - 2.5px);
width: 5px; height: 10px;
background-color: #444;
}
.clock__frame div:nth-child(1) { transform: rotate(0deg); }
.clock__frame div:nth-child(2) { transform: rotate(15deg); }
.clock__frame div:nth-child(3) { transform: rotate(30deg); }
.clock__frame div:nth-child(4) { transform: rotate(45deg); }
.clock__frame div:nth-child(5) { transform: rotate(60deg); }
.clock__frame div:nth-child(6) { transform: rotate(75deg); }
.clock__frame div:nth-child(7) { transform: rotate(90deg); }
.clock__frame div:nth-child(8) { transform: rotate(105deg); }
.clock__frame div:nth-child(9) { transform: rotate(120deg); }
.clock__frame div:nth-child(10) { transform: rotate(135deg); }
.clock__frame div:nth-child(11) { transform: rotate(150deg); }
.clock__frame div:nth-child(12) { transform: rotate(165deg); }
.clock__frame div:nth-child(13) { transform: rotate(180deg); }
.clock__frame div:nth-child(14) { transform: rotate(195deg); }
.clock__frame div:nth-child(15) { transform: rotate(210deg); }
.clock__frame div:nth-child(16) { transform: rotate(225deg); }
.clock__frame div:nth-child(17) { transform: rotate(240deg); }
.clock__frame div:nth-child(18) { transform: rotate(255deg); }
.clock__frame div:nth-child(19) { transform: rotate(270deg); }
.clock__frame div:nth-child(20) { transform: rotate(285deg); }
.clock__frame div:nth-child(21) { transform: rotate(300deg); }
.clock__frame div:nth-child(22) { transform: rotate(315deg); }
.clock__frame div:nth-child(23) { transform: rotate(330deg); }
.clock__frame div:nth-child(24) { transform: rotate(345deg); }
次に長針と短針と時計の中央に配置する画像にスタイルをあてていきましょう。
.clock__hands div:nth-child(1)
(長針)が高さ50%
で、.clock__hands div:nth-child(2)
(短針)が高さ40%
にしています。
.clock__image
は、時計の中央に配置する画像ですね。100% - 90px
(410px)という大きさにしています。

画像は、お好みのものを用意してください。
.clock__hands {
position: absolute;
top: 35px; left: 35px;
width: calc(100% - 70px); height: calc(100% - 70px);
}
.clock__hands div {
position: absolute;
top: 0; left: 0;
width: 100%; height: 100%;
}
.clock__hands div:after {
content: ""; display: block;
position: absolute;
top: 0; left: calc(50% - 5px);
width: 10px;
background-color: #444;
border-radius: 5px;
}
.clock__hands div:nth-child(1):after { height: 50%; }
.clock__hands div:nth-child(2):after { height: 40%; top: 10%; }
.clock__image {
position: absolute;
top: 45px; left: 45px;
width: calc(100% - 90px); height: calc(100% - 90px);
background-image: url(/* お好きな画像を指定 */);
background-size: auto 100%;
background-position: center;
background-repeat: no-repeat;
}
このままだと、止まったままなので時計っぽくありませんね。(特に画像を重ねているので)
なので、時計の針を動かしていきましょう。
.clock__hands:nth-child(2)
(短針)が360deg
、.clock__hands:nth-child(1)
(長針)が360 * 12 = 4320deg
回転するようにします。(これよりいい方法がありますが脳死でいきます)
時計なので、イージングにはlinear
(一定のスピードでアニメーション)を使っています。
.clock__hands div:nth-child(1) { animation: rotate4320 30s linear 0s infinite; }
.clock__hands div:nth-child(2) { animation: rotate360 30s linear 0s infinite; }
rotate360 {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
rotate4320 {
from { transform: rotate(0deg); }
to { transform: rotate(4320deg); }
}
どうでしょうか?
↓のような時計ができましたか?できましたね。はい。次。
次に行く前に一旦、.clock
をdisplay:none
しておいてください。
回想シーンパネルのようなもの

次は↑の円状の回想シーンのパネルのようなものを作っていきましょう。
まず、↓のマークアップを追加してください。
<main class="stage">
<div class="stage__inner">
<section class="clock"></section>
<section class="memories memories_layer_1">
<div class="memories__image memories__image_type_1"></div>
<div class="memories__frame"></div>
</section>
<section class="memories memories_layer_2">
<div class="memories__image memories__image_type_2"></div>
<div class="memories__frame"></div>
</section>
<section class="memories memories_layer_3">
<div class="memories__image memories__image_type_3"></div>
<div class="memories__frame"></div>
</section>
<section class="memories memories_layer_4">
<div class="memories__image memories__image_type_4"></div>
<div class="memories__frame"></div>
</section>
<section class="memories memories_layer_5">
<div class="memories__image memories__image_type_5"></div>
<div class="memories__frame"></div>
</section>
</div>
<div class="stage__filter"></div>
</main>
先に縁の部分を作っていきましょう。
.memories
の大きさは.clock
と同様に500px x 500px
です。
ここでは一旦、.memories__image_type_2
~ .memories__image_type_5
をdisplay:none
で非表示にします(重なってしまって、これからデザインが確認しづらいため)
縁部分の内側(.memories__frame:before
)が通常の線で、外側(.memories__frame:after
)が波のような滑らかな線にしていきます。

滑らかな線は、border-top
とborder-bottom
のような2点だけを指定するできます。
.memories {
position: absolute;
top: calc(50% - 250px); left: calc(50% - 250px);
width: 500px; height: 500px;
}
.memories__image_type_2,
.memories__image_type_3,
.memories__image_type_4,
.memories__image_type_5 { display: none; }
.memories__frame {
position: absolute;
top: 0; left: 0;
width: 100%; height: 100%;
}
.memories__frame:before,
.memories__frame:after {
content: ""; display: block;
position: absolute;
border-radius: 50%;
box-sizing: border-box;
}
.memories__frame:before {
top: 25px; left: 25px;
width: calc(100% - 50px); height: calc(100% - 50px);
border: solid 1px #444;
}
.memories__frame:after {
top: 0; left: 0;
width: 100%; height: 100%;
border-top: solid 10px #444;
border-bottom: solid 10px #444;
}
次にパネルの画像にスタイルをあてていきます。
ちょっと透明にしているのは、あとでレイヤー間を通り過ぎる感覚をより際立たせるためです。
あと、内側にbox-shadow
で影をつけて回想シーン感をまた出します。

画像はお好みのものを。
.memories__image {
position: absolute;
top: 50px; left: 50px;
width: calc(100% - 100px); height: calc(100% - 100px);
border-radius: 50%;
background-size: cover;
background-position: center;
opacity: 0.8;
}
.memories__image:after {
content: ""; display: block;
position: absolute;
width: 100%; height: 100%;
border-radius: 50%;
box-shadow: 0 0 40px #333 inset;
}
.memories__image_type_1 { background-image: url(/* お好きな画像を指定 */); }
.memories__image_type_2 { background-image: url(/* お好きな画像を指定 */); }
.memories__image_type_3 { background-image: url(/* お好きな画像を指定 */); }
.memories__image_type_4 { background-image: url(/* お好きな画像を指定 */); }
.memories__image_type_5 { background-image: url(/* お好きな画像を指定 */); }
このままだとつまらないので、滑らかな線(memories__frame:after
)を回転させましょう。
キーフレームはrotate360
を使い回しましょう。
.memories__frame:after { animation: rotate360 3.5s linear 0s infinite; }
ここまできたら、.clock
と.memories__image_type_2
~ .memories__image_type_5
のdisplay:none
を消してください。
立体空間をすり抜ける
最後にお待ちかねの立体空間をすり抜けるようなアニメーションですが、それを実現するためにperspective
とtransform-style
を使います。
perspective
は、"ユーザの視点" から "コンテンツ(要素)"の距離を指定することができます。
なので、対象の要素が傾いていた場合、perspective
の値が小さければ小さいほど傾きが大きく、perspective
の値が大きければ大きいほど傾きが小さくなります。
詳しくはこちら

transform-style
は、親要素の傾きに対して、子要素は3D空間の位置を保持するかを指定できます。
デフォルトではflat
ですが、preserve-3d
にするとパララックス効果(視差効果)を出すことができます。
で、まず視点の基準として.stage
にperspective
を指定し、各3D空間に配置する要素の親要素である.stage__inner
にtransform-style
を指定します。
.stage { perspective: 20px; }
.stage__inner { transform-style: preserve-3d; }
次に.clock
と.memories_layer_1
~ .memories_layer_5
を3D空間の位置に配置しましょう。
translateZ
で100px
間隔を空けながら、3D空間に配置していきます。

translateZ
を指定すると、perspective
の値により、本来より大きくなったり小さくなったりするので、ある地点で本来の大きさになるようにscale
で調整します。
.clock { transform: translateZ(50px) scale(calc(1 - (50 / 100))); }
.memories_layer_1 { transform: translateZ(150px) scale(calc(1 - (150 / 200))); }
.memories_layer_2 { transform: translateZ(250px) scale(calc(1 - (250 / 300))); }
.memories_layer_3 { transform: translateZ(350px) scale(calc(1 - (350 / 400))); }
.memories_layer_4 { transform: translateZ(450px) scale(calc(1 - (450 / 500))); }
.memories_layer_5 { transform: translateZ(550px) scale(calc(1 - (550 / 600))); }
あとは"ユーザの視点"を行ったり来たりするためにcamera
キーフレームを使います。
行き来するのは、camera
キーフレームを0% ~ 100%
を100% ~ 0%
にするだけなので、キーフレームをカンマで区切り、reverse
オプションで100% ~ 0%
にすることができます。
あとsway
キーフレームで斜めに揺らして、より立体感と浮遊感を表現しています。

.stage {
animation:
camera 8s ease-in-out 0s forwards,
camera 4s ease 8s reverse forwards;
}
.stage__inner { animation: sway 0.7s ease-in-out 0s alternate infinite; }
camera {
from { perspective: 20px; }
to { perspective: 600px; }
}
sway {
from { transform: translate(3px, 3px); }
to { transform: translate(-3px, -3px); }
}
これで完成したはずです。
記述ミスや記述漏れがあるかもしれませんので、完成したコードはこちらにありますのでご確認ください。
さいごに
今回はperspective
を使った演出を解説しましたが、いかがでしたでしょうか?
立体的に見せるだけで表現の幅がかなり広がりましたね。
また、今回の回想シーンのような表現にも注目して欲しいなと思います。対象の作品(今回はリゼロ)の雰囲気をいかに出せるかがキャラクターイラストを使った演出のキモだと僕は思います。
ですが、実際のページで使うには、まだパフォーマンスが良くないのでWebGLでの演出なんかの参考になれば幸いです。
次回も何か面白いアニメーションを用意するので、よければ見てください。
じゃーねー
