Edited at

iOSでposition:fixedした要素がスクロール中だけz-indexを無視して前面に表示されてしまうバグ

More than 5 years have passed since last update.

ブラウザの表示領域に対して要素の位置を固定してくれるposition: fixed;は、表示領域が限られるスマートフォンでこそ使いどころがたくさんあるのだが、(特にAndroidで)バグが多くて実用にはまだまだ慎重にならざるを得ない。

今回は、iOSで遭遇したバグについて記述しておく。


症状

position: fixedを指定した要素がz-indexを無視する。

精確に説明すると、position: fixedを指定した要素が、表示領域外にある部分が、スクロールされて表示領域に入ってきたときに、スクロールされている間だけ、z-indexが無視されて、より大きなz-indexが指定されている(即ちより手前の)要素より前面に表示される。

実際のコードをご覧いただこう。

   <div class="contents">ここに通常のコンテンツ</div>

<div class="bg"></div><!-- 背景表示のための要素 -->
<div class="footer">
iPhoneだと通常スクロールしなければ見えない要素
</div>

   .contents {

position: relative;
z-index: 10;
height: 500px;
}
.bg {
position: fixed;
z-index: 1;
top: 0px;
left: 0px;
width: 100%;
height: 100%;
background-image: url(bg.jpg);
}
.footer {
position: relative;
z-index: 10;
height: 200px;
background-color: #fff;
}

div.footerは、スクロールしなければ見えない位置にある。

スクロールすると見えるはずなのだが、なぜかdiv.bgの下に隠れて見えないのだ。そしてこの現象が発生するのは、 スクロールしている間だけ であり、スクロールが停止した段階で、前面に正しく表示される。

また、div.footerがスクロール前に表示領域内に一部でも見えていれば、この現象は発生しない。

現象を確認した環境


  • iOS7 Safari, Chrome

  • iOS6 Safari, Chrome

iOS版 Operaではこの現象は見られなかった。


position:fixedを使った理由

なぜ、div.contentsbackgroundを設定するのではなく、div.bgという要素をわざわざ用意しているかというと、背景画像をスクロールさせずに固定位置に配置したかったからである。

背景画像を固定にするためのプロパティbackground-attachment: fixedは、スマートフォンではうまく機能しないケースが多いため、このようなハックが出回っているが、そのために別のバグにでくわしたというわけだ。


対応策

下に隠れてしまうdiv.footerに以下のcssを指定することで解消される。

.footer {

-webkit-transform: translate3d(0,0,0);
}

ただし、translate3dを設定することによって、Androidでは全く別のバグを誘発しうるので注意を要する。

必要に応じて、JavaScriptでユーザーエージェントで判定してclass属性を出し分けるなどして、このCSS記述がiOSのときだけ反映されるように工夫してやる。


position:fixedくらい、そろそろ普通に使いたい。background-attachement:fixedも。