Michael Charles Aubrey

https://MichaelCharl.es/Aubrey

Chrome 129における`container-type: inline-size`の予期せぬ変更への対応

Chrome 129における`container-type: inline-size`の予期せぬ変更への対応

Michael Charles Aubrey // Thu Oct 03 2024

Chrome 129 では、container-type: inline-sizeを持つ要素に影響を与える Container Queries の動作が変更されました。この変更は小さいものの、Web アプリのレイアウトを崩す可能性があります。この記事では、何が変更されたのか、以前はどのように動作していたのか、そして Chrome 129 からどのように動作するようになったのかを説明します。

変更点

Chrome 129 以前では、container-type: inline-sizeは暗黙的に以下の効果がありました:

  1. 絶対配置される要素のための包含ブロックを作成
  2. 新しい重ね合わせコンテキストを確立

これを説明するために、以下の例を見てみましょう:

<!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 以前では、上記のコードは以下のように表示されました:

黒い境界線で囲まれた白い四角形を含むウェブページのスクリーンショット。白い四角形の上には3つの小さな四角形が重なっています。下に緑の四角形、中間に赤、上に青があります。すべての色付きの四角形は白い四角形の黒い境界線の中に収まっています。

黒い境界線で囲まれた.container div の子要素は絶対配置されています。child-2(緑の div)はleft: 0で配置されていますが、親要素である.container div の左側の境界線に合わせて配置されています。これは、Chrome 128 以前では、container-type: inline-sizeが暗黙的に絶対配置された子要素の包含ブロックを作成していたためです。

さらに、container-type: inline-size要素は暗黙的に新しい重ね合わせコンテキストを作成し、結果として緑が一番下、赤が中間、青が一番上に表示されています。

しかし、Chrome 129 では、同じ HTML と CSS は以下のように表示されます:

黒い境界線で囲まれた白い四角形を含むウェブページのスクリーンショット。白い四角形の上には3つの小さな四角形が重なっています。下に緑の四角形、中間に青、上に赤があります。緑の四角形は白い四角形の黒い境界線の外にはみ出しています。

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