Mac SafariでbxSliderが動作しているページを見ると文字がチラつく問題に対する考察と対策。

20150807_image01

こんにちは、夏なんていらねえよ、アンドレです。

さて、Web制作の現場において、スライドショーの実装というのはよくあるご要望の1つであり、その際にプラグインにお世話になることも多いかと思います。bxSliderはその定番プラグインの1つとして、弊社内でもよく使用しています。
しかしながら表題で述べている通り、MacのSafariで見ると、スライダーが動く際に文字がチラつくことがあります。結論から言いますと、bxSlider自体に非はなく、Safari特有のバグです。簡単に検証してみます。

環境再現

まず適当にスライドショーを実装し、適当なテキストを含む要素を用意します。オプションにはauto: trueを指定して自動で動くようにしておきます。

(body以下のコード例)


<body>
  <ul class="slide">
    <li><img src="http://placehold.jp/160x120.png"></li>
    <li><img src="http://placehold.jp/160x120.png"></li>
    <li><img src="http://placehold.jp/160x120.png"></li>
  </ul>
  <p>テキストテキストテキストテキスト</p>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script src="//cdn.jsdelivr.net/bxslider/4.1.2/jquery.bxslider.min.js"></script>
<script>
$(function() {
  $('.slide').bxSlider({
    auto: true
  });
});
</script>
</body>

そしてテキストを含むタグ(この場合pタグ)にposition: relativeを指定します。

解決法および原因考察

解決法の1つは、bxSliderのオプションにuseCSS: falseを指定し、jsで動かすことです(デフォルトはCSSのtransitionで動きます)。
そしてもう1つはチラつく要素に対して-webkit-font-smoothing: antialiasedを指定することです。
しかしいずれの解決法にもデメリットがあります。前者はjsでの動作となるためパフォーマンスが落ち、後者は指定した要素の文字が細く見えてしまいます。
後者はfont-weight: boldを指定することである程度相殺できますが、それでもデフォルトとは見え方が違いますし、他ブラウザでは普通に太字になってしまうため、ピンポイントな箇所以外では使いづらいでしょう。

原因考察に移ります。スライドショーのスライド動作はCSSのtransform: translate3dで動いていて、translate3dはGPUアクセラレーションで処理されています。
その結果、恐らくこちらの事例のように、GPUアクセラレーションで描画が更新される際、特定のCSSプロパティを指定しているとその要素が巻き込まれてしまい(もともとCPUで処理されているものが、一緒にGPUで処理されてしまう)、描画がCPUで行われるかGPUで行われるかの切り替わりによってチラつく、というところだと思います。
ちなみに特定のCSSプロパティと言ったのは、position: relative以外に、opacityで透過度を指定することでも同じ現象が起こるからです。他にも影響するものはありそうです。

…と、以上で締められればよかったのですが、今回のサンプルをJSFiddleを介して見られるようにしようと、JSFiddle上で動作させてみると再現されず、また先のブラウザネイティブ環境でもオプションのpagerとcontrolsを切ると再現されないので、完全に何がダメ、ということは言い切れなさそうです…。何か分かった際にはまた追記したいと思います。

まとめ

結局のところ、GPUアクセラレーションが働く際に起こる可能性がある現象なので、単純にCSSのtransitionを使うだけでも留意する必要があります。
transitionをバリバリ使って動きのあるサイトを制作する際には、MacのSafariでプレビューしながら進めたほうが良さそうです。