更新 : 2018年11月21日(水)
iOS11以降では問題なく動作することが確認できました。
以下の記事はiOS10以前のSafariのみの挙動になります。
iOS10以前に対応する場合のみ参考にしていただければ幸いです。
CSS3のアニメーションが登場して久しい今日この頃。
これまでアニメーションはJavaScriptで付けていたという人も、どんどんCSSで付けるようになってきたのではないでしょうか?
CSSのアニメーションは本当に簡単に付けられるので、プログラミングに馴染みのない人でも手を出しやすくなったのも良いですよね。
特にユーザー側のメリットとして大きいのがCSSでアニメーションを付けた方が動作が軽いということなんです。
「なんで軽くなるの?」という方は、こちらの記事なんか分かりやすくまとまっているのでぜひ読んでみてください。
「CSSでアニメーションした方が簡単だし軽いんなら、
もうアニメーションは全部CSSで付けちゃおう!」
と言ってアニメーションはすべてCSSで付けるというのは間違いではないのですが、これ実はちょっとした落とし穴があるので今回はそんなお話を。
画面外から要素が入ってくるアニメーション
例えばこんなアニメーションを付けることがあると思います。
ソースはこんな感じです。
<p><button type="button" name="button" id="click_me">アニメーション</button></p> <div class="page_wrap"> <div class="container"> <div class="item"></div> </div> </div>
.item { width: 120px; height: 120px; background: url(nesoberikochirawomiruneko.jpg) no-repeat 50% 50%; background-size: cover; transition: transform 0.6s ease-out; transform: translate3d(375px, 0, 0); }
$(function() { $('#click_me').on('click', function() { $('.item').css('transform', 'translate3d(0, 0, 0)'); }); });
transformの値を付与するのにjsを使っていますが、アニメーションの動作自体はCSSのtransitionとtransformで行っています。
一見特に何も問題ないように思えますが、ではこれをiPhoneで見てみましょう。
iOS Safariの挙動
はい、ボタンを押すとアニメーションせずに、アニメーションが終わったくらいの時間にパッと現れやがります。
この挙動はiOSのみ(iOS8〜10まで検証しましたが結果は同じ)で、AndroidやPCブラウザでは普通にアニメーションされます。
一体何が起こっているのでしょう??
GPUレンダリングのせい?
これいろいろ調べてみたんですが、正直はっきりとした原因は分からないままなんですよね……
なのでここからは僕の憶測でしかないのですが。
通常DOMにある要素は画面内にあろうがなかろうがすべてレンダリングされるのが基本です。
ところがCSSアニメーションをした途端、GPUレンダリングに切り替わります。
その時に画面外にある要素はレンダリングをしないような仕様になっているのではないかと推測しています。(メモリの使用率を削減するため?)
アニメーション開始時にレンダリングされていない状態でアニメーションが始まるので、アニメーション中はその状態が続きます。
アニメーションが終わると、元のCPUレンダリングに切り替わるので、そのタイミングで表示される。
といった仕組みではないでしょうか?
(もし詳しく分かる方がいましたら、ご教授いただきたいです…!)
対処法
CSSでアニメーションする以上、これは避けられない現象です。
なのでおとなしくJavaScriptでアニメーションするようにしましょう(笑)
$(function() { $('#click_me').on('click', function() { $('.item').animate({ transform: 'translate3d(0, 0, 0)' }); }); });
jQueryを使えばこんな感じに短く書けてしまいます。
余談
余談ですが、元々iOSってメモリ使用を極限まで削る仕組みになってるんですよね。
これはiOSアプリの話にはなりますが、例えばテーブルなんかいい例で、iOSアプリでは画面の中に収まっている分のセルしか生成しない仕組みになっているんです。
じゃあはみ出た分のセルはどうしているのかと言うと、仮に上にスクロールしたとしたら、上に見えなくなったセルは下に移動して、セルを使いまわす仕組みになっているんです。
なので今回の件はiOSのどのバージョンでも起こってしまっているあたり、バグではなく似たようなiOS特有の仕様によるものなんじゃないかと思います。
まとめ
基本的にアニメーションはCSSで付けるようにしてほぼ問題ありません。
ただごく稀に今回のような不具合が起こることがあるため、その時は多少パフォーマンスが低下したとしてもおとなしくJavaScriptでアニメーションを付けるようにしましょう!
念のため確認用に今回のデモファイルをアップしておきましたので、参考までに。
おわりっ。
コメント
iOS12のChromeではこのアニメーション動かず…。
この仕様どうにかならないものか…(笑)。
コメント頂きありがとうございます。
iOS12のChromeだと僕の環境では普通に動いたのですが、動かないですか?
そして今改めて検証してみたところ、なんとiOS11, 12のSafariでは問題なく動いていました!(笑)
どうやらiOS10以前のバグだったのかもしれませんね…。