position:fixed;とtransformのスマホ挙動
position:fixed;で負のz-indexを使用して要素を疑似的な背景にしようとした際の話。
それと同一階層の要素や別の階層の子要素などにtransform:rotate3d;を使用すると、position:fixed;がz-indexが負の値にもかかわらず、transform:rotate3d;の要素が隠れてしまう。
スマホで以上のような現象を確認した。スマホだけ。PCには問題がない。
例として、animate.cssでflipInやflipOutをかけようとして、この条件が満たされてしまうと発現する。
試しに以下のようなコード体系でコーディングをしてみる。
テスト用のコード
<style> .content{ /* レイアウトのスタイルなんたら */ } .image{ /* レイアウトのスタイルほにゃらら */ } .text{ /* レイアウトのスタイルほげほげ */ } .fix-background{ width:100%; height:100%; background:#CCC; position:fixed; top:0; left:0; right:0; bottom:0; z-index:-1; } </style> <div id="container"> <article class="content"> <!--↓このimageをanimateさせようとする--> <div class="image flipInY animated"><img src="image.jpg" alt="image" /></div> <div class="text"> <p>上記imageに対して、animate.cssのプロパティをかけてあげるとあら不思議。</p> <p>スマホで見たときに下のfix-backgroundにimageが隠れてしまう!</p> </div> </article> <div class="fix-background">position:fixed;での疑似背景</div> </div>
上記の例だとtransform:rotate3d;のかかった「image」要素は、position:fixed;とz-index:-1;をかけた「fix-background」要素の後ろ側に隠れてしまう。
animate.cssでrotate3dがかかっているためではないかと早い段階で気づいたものの・・・。
単なる要素の重なりの問題かと思って、上記の「image」にposition relativeとz-indexをかけてもうまくはいかない。
transform:rotate3d;自体が上記のコードでは、animate.cssがかかっている「image」にしか入っていないわけで・・・。
こいつだけかと思いきや、translate3dとかの3D系のtransformの要素に関してはアニメーションなどの「処理」が行われると同じことが起きる。
これがスマホだけで起こるというのもなんとも奇妙な話である。
???
こいつの特定と修正で小一時間悩んだ。
調べた結果
いわゆるスマホのブラウザレンダリングのGPUアクセラレーションに引っかかっているらしい。
3D系のtransformが「処理」される前に、祖先要素のどこかで静的にGPUアクセラレーションを有効化させておく必要がある。
要は処理する前に準備しといてくださいねーってこと。
これしないと、position:fixed;の疑似背景に、いくら負のz-indexをかけようが意味がない。
そして、これに対策を施すのであれば、以下のようにコードとなる。
<style> .content{ /* レイアウトのスタイルなんたら */ transform:translate3d(0,0,0); } .image{ /* レイアウトのスタイルほにゃらら */ } .text{ /* レイアウトのスタイルほげほげ */ } .fix-background{ width:100%; height:100%; background:#CCC; position:fixed; top:0; left:0; right:0; bottom:0; z-index:-1; } </style> <div id="container"> <article class="content"><!--←これ--> <div class="image flipInY animated"><img src="image.jpg" alt="image" /></div> <div class="text"> <p>これでスマホでもうまいことアニメーションするぞ!</p> </div> </article> <div class="fix-background">position:fixed;での疑似背景</div> </div>
上記では静的なtransform:translate3d(0,0,0);をanimate.cssを使う要素の親要素にかけている。
transform:translate3d(0,0,0);といいつつ、GPUアクセラレーションを有効化させられるCSSプロパティならperspectiveでも何でもいいっぽい。
GPUアクセラレーションの有効化をワイルドカードでかける習慣が自分にはないので遭遇した問題・・・といえばそれまでですが、備忘録として記載しておきます。