Chrome 22 では、position:fixed
要素のレイアウト動作が以前のバージョンと若干異なります。すべての position:fixed
要素が新しいスタッキング コンテキストを形成するようになりました。これにより、一部のページの重ね順序が変更され、ページ レイアウトが崩れる可能性があります。新しい動作は、モバイル デバイスの WebKit ブラウザ(iOS Safari と Android 版 Chrome)の動作と一致します。
スタッキング
ページ上の要素の深度順序を決定する z-index
は、誰もが知っていて愛用しているものです。ただし、すべての Z インデックスが同じではありません。要素の z-index
は、同じスタッキング コンテキスト内の他の要素に対する要素の順序のみを決定します。ページ上のほとんどの要素は単一のルート スタッキング コンテキストにありますが、z-index
値が自動以外の絶対位置または相対位置の要素は、独自のスタッキング コンテキストを形成します(つまり、すべての子要素は親内で z 順序付けされ、親の外部からのコンテンツとインターリーブされません)。Chrome 22 以降では、position:fixed
要素も独自のスタッキング コンテキストを作成します。
スタッキング コンテキストの概要については、こちらの MDN の記事をご覧ください。
position:fixed
を 新しい position:sticky 属性と比較します。なお、position:sticky
は常に新しいスタッキング コンテキストを作成します。
目的
モバイル ブラウザ(Mobile Safari、Android ブラウザ、Qt ベースのブラウザ)では、position:fixed 要素が独自のスタッキング コンテキストに配置されます。これは、特定のスクロールの最適化が可能になり、ウェブページのタップ レスポンスが大幅に向上するため、iOS5、Android Gingerbread など、しばらく前から行われています。この変更は、以下の 3 つの理由によりパソコンに導入されます。
- 「モバイル」ブラウザと「パソコン」ブラウザでレンダリング動作が異なることは、ウェブ作成者にとって障害となります。可能な限り、CSS はどこでも同じように動作する必要があります。
- タブレットの場合、「モバイル」と「パソコン」のどちらのグルーピング コンテキスト作成アルゴリズムが適切であるかは明確ではありません。
- モバイルからパソコンにスクロール パフォーマンスの最適化を適用することは、ユーザーと作成者の両方にメリットがあります。
変更の詳細
さまざまなレイアウトの動作を示す例: https://codepen.io/paulirish/pen/CgAof
この変更により、両方のバージョンが右側のバージョンのようにレンダリングされるようになります。
この例では、緑色のボックスには z-index: 1
、ピンクのボックスには z-index: 3
、オレンジ色のボックスには z-index: 2
が含まれています。青いボックスはオレンジ色のボックスの祖先で、position:fixed
があります。
青いボックスに独自のスタッキング コンテキストが割り当てられている場合、オレンジ色のボックスの z-index
は青いボックスのスタッキング コンテキストを基準に計算されます。青いボックスの z-index
は auto
であるため、ルート スタッキング コンテキストでのスタッキング レベルは 0 になります。つまり、オレンジ色のボックスは、ルート コンテキストで z インデックスが 1 と 3 の緑色とピンクのボックスの後ろに配置されます。
青いボックスに独自のスタッキング コンテキストがない場合、オレンジ色のボックスの z-index
は、(緑色とピンクのボックスとともに)ルート スタッキング コンテキストを基準に計算されます。そのため、オレンジ色のボックスはピンク色と緑色のボックスと交互に配置されます。
スタッキング コンテキストの作成条件(およびスタッキング コンテキストの一般的な動作)について詳しくは、こちらの MDN の記事をご覧ください。この例では、右側のバージョンでは、青いボックスの不透明度が 1 未満であるため、常に青いボックスに独自のスタッキング コンテキストが設定されています。変更された動作により、別個のスタッキング コンテキストを作成するための別の条件(要素が position:fixed である)が実質的に追加されます。
テストと今後
ページが変更されるかどうかをテストするには、Chrome の about:flags
に移動し、[固定位置要素がスタッキング コンテキストを作成] をオンまたはオフにします。どちらの場合でもレイアウトが同じ動作をすれば、問題ありません。問題がなければ、このフラグを有効にした状態で問題がないことを確認してください。このフラグは Chrome 22 のデフォルトになります。
この変更により、position:fixed サブツリー内のコンテンツと外部からのスクロールしないコンテンツを交互に表示する機能が削除されます。ウェブ デベロッパーが意図的にこのようなことを行っている可能性は低く、複数の position:fixed 要素に DOM の異なる部分を指定することで、同じ効果を得ることができます。たとえば、次の 2 つの例を考えてみましょう。
https://codepen.io/wiltzius/pen/gcjCk
このページでは、position:fixed 要素の 2 つの子 div(overlayA と overlayB)を、1 つは別のコンテンツ div の上に、もう 1 つは同じコンテンツ div の下に配置しようとしています。しかし、position:fixed 要素は独自のスタッキング コンテキストであり、その要素(およびそのすべての子要素)はコンテンツ div の上に完全に配置されるか、コンテンツ div の下に完全に配置されるため、この操作は不可能になりました。この例は Chrome 21 以前では動作しますが、Chrome 22 では動作しません。
この問題を解決するには、2 つのオーバーレイを独自の position:fixed 要素に分割します。それぞれが独自のスタッキング コンテキストであり、一方はコンテンツ div の上に、もう一方はコンテンツ div の下に配置できます。Chrome 21 と 22 で動作する修正済みの例をご覧ください。
https://codepen.io/wiltzius/pen/vhFzG
Chrome は、position:fixed 要素が独自のスタッキング コンテキストを作成できる最初のデスクトップ ブラウザです。関連する標準は CSS の z-index 仕様です(https://www.w3.org/TR/CSS21/zindex.html などをご覧ください)。モバイルとパソコンのブラウザの違いについて、どのような対応をすべきかについてはまだコンセンサスがありません。しかし、モバイルとパソコンで 2 つの異なる動作が混在することで生じる混乱を考慮し、Chrome では当面、両方のプラットフォームでこの単一の動作に移行することを選択しました。
2012 年 10 月 1 日更新: この記事の元のバージョンでは、CSS z-index
仕様がすでに変更され、position: fixed 要素の新しい動作が反映されていると説明されていました。これは正確ではありません。www-style リストで議論されていますが、現時点では仕様に変更はありません。