コンテナクエリ

目次

コンテナクエリとは

ブラウザの横幅などに応じて応じて異なるスタイルを適用するのが メディアクエリ ですが、画面内の矩形領域(コンテナ)の横幅等に応じて異なるスタイルを適用するのが コンテナクエリ です。

基本的な使用例

コンテナの container-typeinline-size または size を指定し、@container で異なるスタイルを指定する条件とスタイルを指定します。下記の例では通常コンテナ(#c1)内のテキストは赤色ですが、横幅が600px以上のコンテナ(#c2)内のテキストは青色になります。

CSS
.container {
  container-type: inline-size;
  border: 1px solid #ccc;
  padding: .2rem;
  margin-bottom: .2rem;
}
#c1 { width: 700px; }
#c2 { width: 500px; }
.text { color: red; }
@container (width > 600px) {
  .text { color: blue; }
}
HTML
<div id="c1" class="container">
  <div class="text">Card Title</div>
</div>
<div id="c2" class="container">
  <div class="text">Card Title</div>
</div>
表示
Card Title
Card Title

コンテナ名指定

通常は最も近い親コンテナをルールの対象としますが、container-name でコンテナ名を付けてどの要素をルールの対象とするか指定することができます。下記の例では、最も近い親 (.my-sub-container) ではなく名前指定した .my-container の横幅に応じてスタイルが変わります。

CSS
.my-container {
  resize: horizontal;
  border: 1px solid #ccc;
  padding: 1rem;
  overflow: hidden;
  container-name: my-container;
  container-type: inline-size;
}
.my-sub-container {
  resize: horizontal;
  border: 1px solid #ccc;
  padding: 1rem;
  overflow: hidden;
}
@container my-container ( width < 400px ) {
  .my-target { color: red; }
}
HTML
<div class="my-container">
  <div class="my-sub-container">
    <div class="my-target">
      AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    </div>
  </div>
</div>
表示
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

コンテナタイプと名前の同時指定

container でコンテナ名とコンテナタイプを同時に指定することができます。

CSS
.container {
  /* container-name: my-card; */
  /* container-type: inline-size; */
  container: my-card / inline-size;
}

コンテナクエリ単位

コンテナクエリ内では下記の長さの単位を使用できます。

and, or, not

クエリに and, or, not を使用することができます。

@container my-card (600px < width) and (width < 1000px) { ... }
@container my-card (width < 600px) or (1000px < width) { ... }
@container my-card not (width < 600px) { ... }

スクロール状態クエリ(scroll-state())

Chrome 133 でスクロール状態によるクエリがサポートされました。container-type には scroll-state を指定します。詳細は CSS scroll-state()(↗) を参照してください。

@container scroll-state(state) {
  ...
}
state =
    stuck: stuck-params
  | snapped: snap-params
  | scrollable: scrollable-params
stuck-params =
  none | top | right | bottom | left | block-start | inline-start | block-end | inline-end
snap-params =
  none | x | y | block | inline
scrollable-params =
  none | top | right | bottom | left | block-start | inline-start | block-end | inline-end
  | x | y | block | inline
stuck
要素が position: sticky でスクロールが指定した方向にスタックされている時にスタイルを適用します。
snapped
要素が scroll-snap-type で指定した方向にスナップされている時にスタイルを適用します。
scrollable
要素が指定した方向にスクロール可能な時にスタイルを適用します。

スタック(stuck)の例

下記の例では stuck を用いて、h1 要素がページ上部にスタックされた時に背景色を変更しています。

CSS
.container {
  width: 400px;
  height: 400px;
  border: 1px solid #ccc;
  overflow-y: auto;
  .stuck-top {
    container-type: scroll-state;
    position: sticky;
    top: 0px;
    margin-top: 100px;
    h1 {
      @container scroll-state(stuck: top) {
        background-color: #ddd;
      }
    }
  }  
}
HTML
<div class="container">
  <div class="stuck-top">
    <h1>Lorem ipsum</h1>
  </div>
  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. ...</p>
  ...
</div>
表示
Lorem ipsum

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Magnam, sequi. Deleniti exercitationem veritatis, voluptatem ratione quis quia rerum corrupti explicabo aperiam nisi ullam voluptate neque quasi culpa ducimus perferendis vel.

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Magnam, sequi. Deleniti exercitationem veritatis, voluptatem ratione quis quia rerum corrupti explicabo aperiam nisi ullam voluptate neque quasi culpa ducimus perferendis vel.

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Magnam, sequi. Deleniti exercitationem veritatis, voluptatem ratione quis quia rerum corrupti explicabo aperiam nisi ullam voluptate neque quasi culpa ducimus perferendis vel.

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Magnam, sequi. Deleniti exercitationem veritatis, voluptatem ratione quis quia rerum corrupti explicabo aperiam nisi ullam voluptate neque quasi culpa ducimus perferendis vel.

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Magnam, sequi. Deleniti exercitationem veritatis, voluptatem ratione quis quia rerum corrupti explicabo aperiam nisi ullam voluptate neque quasi culpa ducimus perferendis vel.

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Magnam, sequi. Deleniti exercitationem veritatis, voluptatem ratione quis quia rerum corrupti explicabo aperiam nisi ullam voluptate neque quasi culpa ducimus perferendis vel.

スナップ(snapped)の例

下記の例ではスナップされているタイトルに対して色を黒にするスタイルを適用しています。

CSS
.snap-container {
  height: 10rem;
  width: 20rem;
  overflow-y: scroll;
  scroll-snap-type: y mandatory;
  border: 1px solid #ccc;
  .snap-content {
    scroll-snap-align: start;
    container-type: scroll-state;
    h1 {
      color: #ccc;
    }
    @container scroll-state(snapped: y) {
      h1 {
        color: #000;
      }
    }
  }
}
HTML
<div class="snap-container">
  <section class="snap-content">
    <h1>Section-1</h1>
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Magnam, sequi. ...</p>
  </section>
  <section class="snap-content">
    <h1>Section-2</h1>
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Magnam, sequi. ...</p>
  </section>
  <section class="snap-content">
    <h1>Section-3</h1>
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Magnam, sequi. ...</p>
  </section>
  <section class="snap-content">
    <h1>Section-4</h1>
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Magnam, sequi. ...</p>
  </section>
</div>
表示
Section-1

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Magnam, sequi. ...

Section-2

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Magnam, sequi. ...

Section-3

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Magnam, sequi. ...

Section-4

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Magnam, sequi. ...

スクローラブル(scrollable)の例

下記の例では上方向にスクロールが可能な時に、画面の右下に [↑] ボタンを表示します。

CSS
.scroll-container {
  width: 400px;
  height: 400px;
  border: 1px solid #ccc;
  overflow-y: auto;
  container-type: scroll-state;
}
.top-button {
  position: fixed;
  bottom: 8px;
  right: 8px;
  margin: 4px;
  padding: 8px 16px;
  background-color: #333;
  color: #fff;
  border: none;
  border-radius: 5px;
  cursor: pointer;
  transform: scaleY(0);
  transition: .3s;
}
@container scroll-state(scrollable: top) {
  .top-button {
    transform: scaleY(1.0);
  }
}
HTML
<div class="scroll-container">
  <button class="top-button" onclick="this.parentElement.scroll({top:0, behavior:'smooth'})">↑</button>
  <div class="scroll-content">
    <div class="h1">Lorem ipsum</div>
    <p>Lorem ipsum dolor sit amet consectetur adipisicing elit...</p>
  </div>
</div>
表示
Lorem ipsum

Lorem ipsum dolor sit amet consectetur adipisicing elit. Adipisci amet, neque accusamus, voluptas labore eveniet consequatur eum non harum molestiae doloremque ipsam a tempora. Ratione impedit dolorem quia cumque quasi.

Lorem ipsum dolor sit amet consectetur adipisicing elit. Adipisci amet, neque accusamus, voluptas labore eveniet consequatur eum non harum molestiae doloremque ipsam a tempora. Ratione impedit dolorem quia cumque quasi.

Lorem ipsum dolor sit amet consectetur adipisicing elit. Adipisci amet, neque accusamus, voluptas labore eveniet consequatur eum non harum molestiae doloremque ipsam a tempora. Ratione impedit dolorem quia cumque quasi.

Lorem ipsum dolor sit amet consectetur adipisicing elit. Adipisci amet, neque accusamus, voluptas labore eveniet consequatur eum non harum molestiae doloremque ipsam a tempora. Ratione impedit dolorem quia cumque quasi.

Lorem ipsum dolor sit amet consectetur adipisicing elit. Adipisci amet, neque accusamus, voluptas labore eveniet consequatur eum non harum molestiae doloremque ipsam a tempora. Ratione impedit dolorem quia cumque quasi.

Lorem ipsum dolor sit amet consectetur adipisicing elit. Adipisci amet, neque accusamus, voluptas labore eveniet consequatur eum non harum molestiae doloremque ipsam a tempora. Ratione impedit dolorem quia cumque quasi.

Lorem ipsum dolor sit amet consectetur adipisicing elit. Adipisci amet, neque accusamus, voluptas labore eveniet consequatur eum non harum molestiae doloremque ipsam a tempora. Ratione impedit dolorem quia cumque quasi.