Chrome 129における`container-type: inline-size`の予期せぬ変更への対応
Chrome 129 では、container-type: inline-size
を持つ要素に影響を与える Container Queries の動作が変更されました。この変更は小さいものの、Web アプリのレイアウトを崩す可能性があります。この記事では、何が変更されたのか、以前はどのように動作していたのか、そして Chrome 129 からどのように動作するようになったのかを説明します。
変更点
Chrome 129 以前では、container-type: inline-size
は暗黙的に以下の効果がありました:
- 絶対配置される要素のための包含ブロックを作成
- 新しい重ね合わせコンテキストを確立
これを説明するために、以下の例を見てみましょう:
<!DOCTYPE html>
<html lang="en">
<head>
<style>
.container {
container-type: inline-size;
width: 300px;
height: 300px;
border: 2px solid black;
padding: 1rem;
margin: 2rem;
contain: layout;
}
.child,
.sibling {
position: absolute;
display: flex;
justify-content: center;
align-items: center;
color: white;
}
.child {
width: 200px;
height: 200px;
}
.child-1 {
background-color: rgba(255, 0, 0, 0.7);
top: 100px;
left: 100px;
z-index: 2;
}
.child-2 {
background-color: rgba(0, 255, 0, 0.7);
top: 30px;
left: 0;
z-index: 1;
}
.sibling {
width: 150px;
height: 150px;
background-color: rgba(0, 0, 255, 0.7);
top: 165px;
left: 50px;
z-index: 1;
}
</style>
</head>
<body>
<div class="container">
<div class="child child-1">Child 1 (z-index: 2)</div>
<div class="child child-2">Child 2 (z-index: 1)</div>
</div>
<div class="sibling">Sibling (z-index: 1)</div>
</body>
</html>
Chrome 129 以前では、上記のコードは以下のように表示されました:
黒い境界線で囲まれた.container
div の子要素は絶対配置されています。child-2
(緑の div)はleft: 0
で配置されていますが、親要素である.container
div の左側の境界線に合わせて配置されています。これは、Chrome 128 以前では、container-type: inline-size
が暗黙的に絶対配置された子要素の包含ブロックを作成していたためです。
さらに、container-type: inline-size
要素は暗黙的に新しい重ね合わせコンテキストを作成し、結果として緑が一番下、赤が中間、青が一番上に表示されています。
しかし、Chrome 129 では、同じ HTML と CSS は以下のように表示されます:
.container
要素の子要素のための包含ブロックは作成されず、そのため絶対配置された要素はコンテナではなくウェブページを基準に配置されます。これにより、緑の四角形は完全にcontainer
からはみ出し、ウェブページの左端に接触しています。
また、新しい重ね合わせコンテキストが作成されなかったため、子要素と兄弟要素の重なり順も変更されました。緑の四角形は依然として一番下にありますが、青の四角形が中間に、赤の四角形が一番上になっています。
なぜこの変更が行われたのか?
Chromium の公式バグトラッカーによると、これは元の仕様におけるデザインミスとされる問題を修正するための意図的な変更でした。
仕様自体はまだ更新されていませんが、ワーキンググループ内での合意に基づき、仕様の変更前にブラウザの動作が変更されました。
この記事を執筆時点(2024 年 10 月 3 日)では、他の主要ブラウザ(Firefox や Safari)はまだ Chrome 129 以前の動作を維持しています。
変更への対応方法
Chrome 129 以前の動作に戻したい場合(そして Firefox と Safari が Chrome の実装に追従するまでの間、ブラウザ間での一貫性を維持したい場合)、container-type: inline-size
を持つ要素に単純にcontain: layout
を追加するだけで良いです。
包含ブロックの動作は必要だが新しい重ね合わせコンテキストは作成したくない場合、代わりにcontainer-type: inline-size
要素にposition: relative
を追加することができます。これにより子要素の包含ブロックは作成されますが、新しい重ね合わせコンテキストは作成されません。ただし、他のブラウザが Chrome に追従するまでは、ブラウザごとに異なる動作となります。
実際に試してみる
以下の CodePen で上記の説明を実際に試すことができます。Chrome 129 以降を使用している場合、.container
スタイルからcontain: layout
を削除すると、上記の 2 番目の画像のようなレイアウトになります。しかし、執筆時点での最新バージョンである Firefox 131 で同じ CodePen を表示すると、contain: layout
の設定に関係なく同じように表示されるはずです。
Chrome 129 のリリースノートにはこの変更についての言及が見つからず、また前述の通りこの変更は仕様の変更に先立って行われたため、私たちは完全に不意を突かれ、私たちの Web アプリの 1 つのレイアウトが大きく崩れてしまいました。この情報が同じ問題を抱える方々の助けになれば幸いです。