Safariでもっさり描画になっていたのを、cssのwill-changeプロパティを指定して改善した話
category:web
Safari(Mac,iOS)だけ妙にサイトの描画が重く、まともに表示もされない症状になって、リリース間際にちょっと焦った話。
結論から言うと下記のサイトの通りで全く同じ症状であることがわかり、JavaScriptの方のコンパイラが原因と思い込んでいたが、cssを1行加えるだけで改善された。
iOS SafariはCSSのfilterプロパティの処理を何故かGPUを使用せずにCPUで行います。...
ウェブティ株式会社 - staffblog iOS SafariはCSSのfilterプロパティを使用すると重くなる
不具合発覚から1時間ほどで解消されたので、記事を残しておいてくれて感謝でした。
cssのwill-changeとは
will-changeプロパティは、domの要素の変更が予測されることをブラウザに助言してあげて、前もって最適化をセットアップすることができるらしい。
変化の前で潜在的に処理を行うことで、そのページの応答を向上させることみたい。
そして今回はアニメーションやイベントきっかけのギミックではなく、単純にグラフィカルなオブジェクトを擬似要素で生成してあげているだけであったが、 safariではfilterプロパティを使った途端、CPU負荷が上がり描画に不具合を発生させていたようだった。
このオブジェクトを他ブラウザのようにGPUレイヤーで生成するようsafariに対して助言するのもこのwill-changeの仕事だったみたい。
.el::before { filter: blur(240px); will-change: filter; }
ただこのwill-change強力な最適化、大量にマシンリソースを使い込んでしまい、使い過ぎるとこの設定のせいでページの速度の低下や多量のリソース消費を引き起こかねないらしい。
重要: will-change は既存の性能問題を扱うための最終解決手段として使用することを意図しています。 予想されるパフォーマンス問題に使用しないでください。
MDN Web Docs mozilla - CSS: カスケーディングスタイルシート / will-change
scriptなどで意図したタイミングでwill-changeを与えてあげて、役目を終えたら(アニメーションの終了など)さっさとwill-changeは削除してしまったほうが良いらしい。
will-changeの代替策
Edgeなどのwill-changeをサポートしてない場合、また今回のようなsafariだけで起きてしまっているだけな場合などは、
.el::before { filter: blur(240px); transform: translateZ(0); }
のように、初期値の3Dのtranslateプロパティ指定してGPUレイヤーを作成してあげたほうが画面に影響もなく、処理も軽くできるようです。
最後に…
今までアニメーションなどを多用してきたけど、意識してこなかったプロパティでした。
ただ、ほんの1行でこれだけの効果を味わうと、2Dや3Dでも滑らかな表現ができそうという期待感があります。
くれぐれも節度を持って、そしてテストもちゃんと時間をかけてあげることにします。