Open8

CSSのコンテナクエリ

ユイト🍓ユイト🍓

コンテナクエリとは

親コンテナのサイズやスタイルに基づいてスタイルを定義できるCSSの機能。
コンテナサイズクエリとコンテナスタイルクエリがある。
今回はコンテナサイズクエリの話。

具体的に親コンテナの何のサイズに基づいてスタイルを定義できる?

@container(条件) {...}の「条件」の部分に使用できる記述子リスト↓

  • width
  • height
  • inline-size
  • block-size
  • aspect-ratio
  • orientation

inline-sizeって?

writing-modeの値によって、widthまたはheightプロパティに対応する。

  • horizontal-〇〇の場合→widthに対応
  • vertical-〇〇の場合→heightに対応

writing-modeの初期値はhorizontal-tbであるため、inline-sizeの初期対応プロパティはwidthになる。

inline-sizewidthに対応する時、block-sizeheightに対応する。
反対にinline-sizeheightに対応する時、block-sizewidthに対応する。

使用できる記述子

  • inline-size
  • max-inline-size
  • min-inline-size

block-sizeって?

writing-modeの値によって、widthまたはheightプロパティに対応する。

  • horizontal-〇〇の場合→heightに対応
  • vertical-〇〇の場合→widthに対応

writing-modeの初期値はhorizontal-tbであるため、block-sizeの初期対応プロパティはheightになる。

使用できる記述子

  • block-size
  • max-block-size
  • min-block-size

aspect-ratioって?

親コンテナの幅と高さの比(アスペクト比)に基づいてスタイルを定義できる。
比とは「ある数が、もう一方の数のどれだけに当たるかを表した数」のこと。
ある要素の幅800px、高さ400pxの場合、幅と高さの比は「800:400」→「2:1」になる。幅は高さの2倍であり、高さは幅の0.5倍である。

aspect-ratioの分子はwidth、分母はheightである。
aspect-ratio: width / height
スラッシュ( / )とheightが省略された場合、heightの規定値は1である。

使用できる記述子

  • aspect-ratio
  • max-aspect-ratio
  • min-aspect-ratio

コード例

@container hoge (aspect-ratio: 3/2) {
   // 3 / 2 = 1.5 親コンテナのアスペクト比が1.5と等しい時
    .hogehoge {
         //style
      }
}
@container hoge (max-aspect-ratio: 3/2) {
   // 親コンテナのアスペクト比が1.5以下の時
    .hogehoge {
         //style
      }
}
@container hoge (min-aspect-ratio: 2) {
   // 2 / 1 = 2 親コンテナのアスペクト比が2以上の時
    .hogehoge {
         //style
      }
}

orientationって?

親コンテナが縦長または横長に基づいてスタイルを定義する。

使用できる記述子

  • portrait(縦長。幅より高さの値が大きい。)
  • landscape(横長。高さより幅の値が大きい。)
ユイト🍓ユイト🍓

基本的な使い方の手順

index.html
<div class="parent">
  <div class="child">子要素だよ〜🍓</div>
</div>

1.基準コンテナを決定

基準コンテナのサイズが変更された際に、再描画されることをブラウザに知らせるため。

レスポンシブ対応したい要素の祖先要素にcontainer-typeまたはcontainerプロパティを指定する。指定された要素は、基準コンテナになり「コンテナコンテキスト(container context)」と呼ばれる。

上記index.htmlの場合、class属性parentを持つdiv要素に指定する↓

style.scss
.parent {
  container-type:inline-size;
  //または、container:parent / inline-size;
}

2.@containerを使って条件を指定

基準コンテナのサイズがどうなったらスタイルを適用するのかの定義する。
例えば、「基準コンテナの幅が500px未満の時」という条件は以下のように書く↓

style.scss
.parent {
  container-type:inline-size;
  //またはcontainer:parent / inline-size;
   max-width:400px;
}

@container (width < 500px) {
 .child {
    background-color:red;
  }
}
ユイト🍓ユイト🍓

注意点

擬似要素は基準コンテナにできない

::before::afterなどの擬似要素は@container{...}内でスタイルを定義することは可能だが、基準コンテナにすることはできない。

🙆OK例

OK.html
<style>
  #container {
    width: 100px;
    container-type: inline-size;
  }
  @container (inline-size < 150px) {
    #inner::before {
      content: "BEFORE";
    }
  }
</style>
<div id=container>
  <span id=inner></span>
</div>

🙅NG例

NG.html
<style>
  #container::before {
    display:block;
    content:"";
    width: 100px;
    height:100px;
    container-type: inline-size;
  }
  @container (inline-size < 150px) {
    #inner {
     background-color:red; /*背景色は赤色にならない*/
    }
  }
</style>
<div id=container>
  <span id=inner></span>
</div>

擬似要素がレスポンシブ対応したい要素の祖先になることがない?

NG.htmlのHTML構造

NG.html
<div id="container">
  #container::before
  <span id="inner"></span>
</div>

#container::before#inner と兄弟の関係だから祖先ではないから、基準コンテナにはならない。

親要素以外も基準コンテナにできる

親要素のみ基準コンテナになるわけではなく、レスポンシブ対応したい要素から見て祖先に当たる要素にcontainer-typeを指定するとそこが基準コンテナとなる↓

<style>
  .ancestor {
    container-type: inline-size;
    width: 100px;
  }

  .parent {
    width: 160px;
  }

  @container (inline-size < 150px) {
    .inner::before {
      content: "BEFORE";
    }
  }
</style>
<div class="ancestor">
  <div class="parent">
    <span class="inner"></span>
  </div>
</div>

最も近い祖先要素が基準コンテナとなる

index.html
<style>
  .container {
    container-type: inline-size;
  }

  .ancestor {
    width: 100px;
  }

  .parent {
    width: 160px;
  }

  @container (inline-size < 150px) {
    /*基準コンテナの幅が150px未満の時*/
    .inner::before {
      content: "BEFORE"; 
    }
  }
</style>
<div class="container ancestor">
  <div class="container parent">
    <span class="inner"></span>
  </div>
</div>

上記index.htmlの場合、.inner::before content: "BEFORE";は表示されない。つまり、基準コンテナはclass属性containerparentを持つdiv要素である。
レスポンシブ対応したい要素(今回の場合、class属性innerを持つspan要素)の複数の祖先要素にcontainer-typeが指定されている場合、最も近い祖先要素が基準コンテナになっていることが分かる。

ユイト🍓ユイト🍓

container-typeとは?

コンテナクエリで使用されるコンテナの種類を指定する。

コンテナの種類↓

  • normal
  • inline-size
  • size

各種類の解説

container-type:normal;

初期値。コンテナサイズクエリのクエリコンテナではないが、コンテナスタイルクエリのクエリコンテナとして残る。
つまり、コンテナサイズクエリはcontainer-typeプロパティを指定する必要があるが、コンテナスタイルクエリは指定しなくて良い。

コンテナスタイルクエリ↓
https://coliss.com/articles/build-websites/operation/css/css-style-queries-begin.html
https://w3c.github.io/csswg-drafts/css-contain-3/#container-style-query

container-type:inline-size;

基準コンテナの幅または高さのどちらか一方の変更のみを監視して、@containerの条件に一致したとき、レスポンシブ対応したい要素のスタイルが適用される。
@containerの条件として使える記述子↓

  • width
  • height
  • inline-size
  • block-size

aspect-ratioorientationは幅と高さ両方の情報がいるので、inline-sizeでは使えない。

分かりにくいので具体的なコード例↓

container-typeの値を変えてみると違いが分かる

W3Cによる正確な解説↓

Establishes a query container for container size queries on the container’s own inline axis. Applies layout containment, style containment, and inline-size containment to the principal box.

container-type:size;

基準コンテナの幅と高さ両方の変更を監視して、@containerの条件に一致したときレスポンシブ対応したい要素のスタイルが適用される。

@containerの条件として使える記述子↓

  • container-type:inline-size;で使える記述子全て
  • aspect-ratio
  • orientation

コード例↓

W3Cによる正確な解説↓

Establishes a query container for container size queries on both the inline and block axis. Applies layout containment, style containment, and size containment to the principal box.

ユイト🍓ユイト🍓

containerプロパティとは?

container-namecontainer-typeを一括で指定できるプロパティ。
スラッシュ( / )で値を区切る。

構文↓

.base-container {
 container:container-name / container-type;
}
ユイト🍓ユイト🍓

container-nameとは?

コンテナに名前をつけることができる。
複数のコンテナを使うときに名前をつけて区別することができる。
省略可能。

名前つける時のルール抜粋

  • 名前は引用符で囲まない
  • スペース区切りで複数の名前を指定できる

名前を引用符で囲まない

🙆OK例→container-name:layou;

🙅‍♂️NG例→container-name:"layout";

スペース区切りで複数の名前を指定できる

例→container-name:width height;

用途がよく理解できていないので、MDNのサンプルコードを載せる↓

.base-container { 
  container-type: inline-size;
  container-name: meta card;
}

@container meta (max-width: 500px) {
  p {
    visibility: hidden;
  }
}

@container card (max-height: 200px) {
  h2 {
    font-size: 1.5em;
  }
}