先日、紙吹雪のように写真が降ってくるjsを書いた時にcss3のAnimationで、rotate3dブラウザによって動作が変わってしまうという現象にハマったので、原因を探ってみました。
この記事の目次
css3で要素を一回転させるコードを書いたが、動かない。
「rotate3d()」で、要素を一回転させるために以下のコードを書いたんですが、firefoxとsafariで動かないという問題が起こりました。ちなみに書いたコードはこんな感じ。
.animated { animation-name: flipInY; animation-timing-function: linear; animation-duration: 3s; animation-fill-mode: both; animation-iteration-count: infinite; } @keyframes flipInY { from { transform:rotate3d(1, 1, 1, 0deg); } to { transform:rotate3d(1,1,1,360deg); } } /* ベンダープレフィックスは省略しています。 */
ブラウザに帰属した問題だったのでベンダープレフィックスを付けてやりゃ問題無いだろうくらいの感覚だったのですが、transformにベンダープレフィックスを付与しても動かないのでかなり困惑。ちなみにAnimationにrotate3d以外にopacityを入れて、下記の様な記述をするとopacityは動作する。。
@keyframes flipInY { from { transform:rotate3d(1, 1, 1, 0deg); opacity:0; } to { transform:rotate3d(1,1,1,360deg); opacity:1; } } /* ベンダープレフィックスは省略しています。 */
なぜ。。ともかくAnimationそのものの記述に誤りは無いっぽい、問題はcss3の記述か呼び出し方にあるのかな、Animationでの呼び出しではなく要素に直接指定する形でrotate3dを指定すると効く。。Animationにすると動かない。。
途中でanimationの最終地点をrotate3d(1,1,1,360deg)にしたら動くことを発見。ここでハッと気が付きました。
結論:Firefox safariとChromeで動きのロジックが違う。
firefoxやsafariなどの一部のブラウザでは、Animationでrotateなどのtrnsformの動作させた時に、着地地点に対して最短の動作をするようになっているみたいです。
つまりどういうことかと言うと、僕がイメージしていた動作は開始位置であるrotate3d(1, 1, 1, 0deg)からdegが0,1,2,3…と変化していくというものでしたが、firefoxやsafariではrotate3d(1, 1, 1, 0deg)がrotate3d(1, 1, 1, 360deg)とみなされていたんです。
単純に数値で追うのではなくて表示に忠実とは、さすがです。
解決法:途中に経由地点を入れてあげる
ここまできたら簡単ですね。経由地点を入れて上げればいいだけなので、keyframesで中継地点にも指定を書き加えて上げればよいというわけです。
@keyframes flipInY { from { transform:rotate3d(1, 1, 1, 0deg); } 25%{ transform:rotate3d(1,1,1,90deg); } 50%{ transform:rotate3d(1,1,1,180deg); } 75%{ transform:rotate3d(1,1,1,270deg); } to { transform:rotate3d(1,1,1,360deg); } } /* ベンダープレフィックスは省略しています。 */
これでどうにか動いてくれるようになりました。
猫の画がくるくる回る by nkmrkisk (@rekid) on CodePen.
番外編:rotate3dの挙動早見表
rotate3dについて勉強 by nkmrkisk (@rekid) on CodePen.
まとめ
css3のAnimationは、まだまだ想定外な挙動だったりが多いし記述が膨大で覚えるのが大変なので、取り急ぎ必要なときはanimate.cssなどのテンプレを利用して修正していくほうが無難な気がしてます。