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アクセラレーションの有効化をワイルドカードでかける習慣が自分にはないので遭遇した問題・・・といえばそれまでですが、備忘録として記載しておきます。
