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つのレイアウトが大きく崩れてしまいました。この情報が同じ問題を抱える方々の助けになれば幸いです。