@container

Baseline 广泛可用 *

此特性已经非常成熟,可以在许多设备和浏览器版本上使用。自 2023 年 2 月起,所有主流浏览器均已支持。

* 此特性的某些部分可能存在不同级别的支持。

@container CSS @ 规则是一种条件组规则,用于将样式应用于包含上下文。样式声明会根据一个条件进行过滤,如果条件为真,则将样式应用于该容器。当被查询的容器尺寸、<style-feature> 或滚动状态发生变化时,将对该条件进行求值。

container-name 属性指定一个查询容器名称的列表。@container 规则可以使用这些名称来筛选要定位的查询容器。可选的、区分大小写的 <container-name> 可以筛选查询所针对的查询容器。

一旦为元素选择了符合条件的查询容器,<container-condition> 中的每个容器特性都将针对该查询容器进行求值。

语法

css
/* With a <size-query> */
@container (width > 400px) {
  h2 {
    font-size: 1.5em;
  }
}

/* With an optional <container-name> */
@container tall (height > 30rem) {
  p {
    line-height: 1.6;
  }
}

/* With a <scroll-state> */
@container scroll-state(scrollable: top) {
  .back-to-top-link {
    visibility: visible;
  }
}

/* With a <container-name> and a <scroll-state> */
@container sticky-heading scroll-state(stuck: top) {
  h2 {
    background: purple;
    color: white;
  }
}

/* Multiple queries in a single condition */
@container (width > 400px) and style(--responsive: true) {
  h2 {
    font-size: 1.5em;
  }
}

/* Condition list */
@container card (width > 400px), style(--responsive: true), scroll-state(stuck: top) {
  h2 {
    font-size: 1.5em;
  }
}

参数

<container-condition>

一个可选的 <container-name> 和一个 <container-query>。如果条件为真,则应用 <stylesheet> 中定义的样式。

<container-name>

可选。当查询的求值为真时,样式将应用到的容器的名称,指定为 <ident>

<container-query>

一组特性,当容器的尺寸、<style-feature> 或滚动状态发生变化时,会对查询容器进行求值。

容器查询中的逻辑关键字

逻辑关键字可用于定义容器条件。

  • and 组合两个或多个条件。
  • or 组合两个或多个条件。
  • not 对条件取反。每个容器查询只允许有一个 'not' 条件,并且不能与 andor 关键字一起使用。
css
@container (width > 400px) and (height > 400px) {
  /* <stylesheet> */
}

@container (width > 400px) or (height > 400px) {
  /* <stylesheet> */
}

@container not (width < 400px) {
  /* <stylesheet> */
}

命名包含上下文

可以使用 container-name 属性为包含上下文命名。

css
.post {
  container-name: sidebar;
  container-type: inline-size;
}

其简写语法是使用 container,形式为 container: <name> / <type>,例如:

css
.post {
  container: sidebar / inline-size;
}

在容器查询中,container-name 属性用于将容器集筛选为具有匹配的查询容器名称的容器。

css
@container sidebar (width > 400px) {
  /* <stylesheet> */
}

有关用法和命名限制的详细信息,请参见 container-name 页面。

描述符

<container-condition> 查询包括尺寸滚动状态容器描述符。

尺寸容器描述符

<container-condition> 可以包含一个或多个布尔尺寸查询,每个查询都包含在一组括号内。尺寸查询包括一个尺寸描述符、一个值,以及(取决于描述符)一个比较运算符。查询始终以内容盒作为比较对象。包含多个条件的语法与 @media 尺寸特性查询的语法相同。

css
@container (min-width: 400px) {
  /* … */
}
@container (orientation: landscape) and (width > 400px) {
  /* … */
}
@container (15em <= block-size <= 30em) {
  /* … */
}
aspect-ratio

容器的 aspect-ratio,计算为容器的宽度与高度之比,表示为 <ratio> 值。

block-size

容器的 block-size,表示为 <length> 值。

height

容器的高度,表示为 <length> 值。

inline-size

容器的 inline-size,表示为 <length> 值。

orientation

容器的方向,可以是 landscape(横向)或 portrait(纵向)。

width

容器的宽度,表示为 <length> 值。

滚动状态容器描述符

滚动状态容器描述符在 <container-condition> 中指定,位于 scroll-state 关键字后的一组括号内,例如:

css
@container scroll-state(scrollable: top) {
  /* … */
}
@container scroll-state(stuck: inline-end) {
  /* … */
}
@container scroll-state(snapped: both) {
  /* … */
}

滚动状态容器描述符支持的关键字包括物理值和流相对值

scrollable

查询容器是否可以在给定方向上通过用户发起的滚动操作(例如拖动滚动条或使用触控板手势)进行滚动。换句话说,在给定方向上是否存在可以滚动的溢出内容?有效的 scrollable 值包括以下关键字:

none

容器不是滚动容器,或者在任何方向上都不能滚动。

top

容器可以向上边缘滚动。

容器可以向右边缘滚动。

bottom

容器可以向下边缘滚动。

left

容器可以向左边缘滚动。

x

容器可以水平地向其左边缘或右边缘之一或两者滚动。

y

容器可以垂直地向其上边缘或下边缘之一或两者滚动。

block-start

容器可以向其块起始边缘滚动。

block-end

容器可以向其块结束边缘滚动。

inline-start

容器可以向其行内起始边缘滚动。

inline-end

容器可以向其行内结束边缘滚动。

block

容器可以在其块方向上向其块起始或块结束边缘之一或两者滚动。

inline

容器可以在其行内方向上向其行内起始和行内结束边缘之一或两者滚动。

如果测试通过,@container 块内的规则将应用于滚动容器的后代元素。

要评估容器是否可滚动,而不关心方向,请使用 not 运算符和 none 值:

css
@container not scroll-state(scrollable: none) {
  /* … */
}
snapped

查询容器是否将沿给定轴贴合到滚动贴合容器祖先。有效的 snapped 值包括以下关键字:

none

容器不是其祖先滚动容器的滚动贴合目标。当实现 snapped: none 查询时,作为滚动容器贴合目标的容器将应用 @container 样式,而非贴合目标应用这些样式。

x

容器是其祖先滚动容器的水平滚动贴合目标,即它正在水平地贴合其祖先。

y

容器是其祖先滚动容器的垂直滚动贴合目标,即它正在垂直地贴合其祖先。

block

容器是其祖先滚动容器的块轴滚动贴合目标,即它正在块方向上贴合其祖先。

inline

容器是其祖先滚动容器的行内轴滚动贴合目标,即它正在行内方向上贴合其祖先。

both

容器同时是其祖先滚动容器的水平和垂直滚动贴合目标,并且在两个方向上都贴合其祖先。如果容器仅沿水平垂直轴贴合其祖先,则不会匹配。它需要同时满足两个条件。

要评估一个具有非 nonesnapped 滚动状态查询的容器,它必须是一个具有滚动容器祖先的容器,且该祖先的 scroll-snap-type 值不为 none。即使没有滚动容器祖先,snapped: none 查询也会匹配。

当滚动贴合容器上触发 scrollsnapchanging 事件时,会进行求值。如果测试通过,@container 块内的规则将应用于该容器的后代元素。

要评估容器是否是贴合目标,而不关心方向,请使用 not 运算符和 none 值:

css
@container not scroll-state(snapped: none) {
  /* … */
}
stuck

查询一个 position 值为 sticky 的容器是否固定在其滚动容器祖先的边缘。有效的 stuck 值包括以下关键字:

none

容器没有固定在其容器的任何边缘。请注意,即使容器没有设置 position: stickynone 查询也会匹配。

top

容器固定在其容器的上边缘。

right

容器固定在其容器的右边缘。

bottom

容器固定在其容器的下边缘。

left

容器固定在其容器的左边缘。

block-start

容器固定在其容器的块起始边缘。

block-end

容器固定在其容器的块结束边缘。

inline-start

容器固定在其容器的行内起始边缘。

inline-end

容器固定在其容器的行内结束边缘。

要评估一个具有非 nonestuck 滚动状态查询的容器,它必须设置了 position: sticky,并且位于一个滚动容器内。如果测试通过,@container 块内的规则将应用于 position: sticky 容器的后代元素。

来自相对轴的两个值可能同时匹配:

css
@container scroll-state((stuck: top) and (stuck: left)) {
  /* … */
}

但是,来自相对边缘的两个值永远不会同时匹配:

css
@container scroll-state((stuck: left) and (stuck: right)) {
  /* … */
}

要评估容器是否固定,而不关心方向,请使用 not 运算符和 none 值:

css
@container not scroll-state(stuck: none) {
  /* … */
}

正式语法

@container = 
@container <container-condition># { <block-contents> }

<container-condition> =
[ <container-name>? <container-query>? ]!

<container-name> =
<custom-ident>

<container-query> =
not <query-in-parens> |
<query-in-parens> [ [ and <query-in-parens> ]* | [ or <query-in-parens> ]* ]

<query-in-parens> =
( <container-query> ) |
( <size-feature> ) |
style( <style-query> ) |
scroll-state( <scroll-state-query> ) |
<general-enclosed>

<style-query> =
not <style-in-parens> |
<style-in-parens> [ [ and <style-in-parens> ]* | [ or <style-in-parens> ]* ] |
<style-feature>

<scroll-state-query> =
not <scroll-state-in-parens> |
<scroll-state-in-parens> [ [ and <scroll-state-in-parens> ]* | [ or <scroll-state-in-parens> ]* ] |
<scroll-state-feature>

<general-enclosed> =
[ <function-token> <any-value>? ) ] |
[ ( <any-value>? ) ]

<style-in-parens> =
( <style-query> ) |
( <style-feature> ) |
<general-enclosed>

<style-feature> =
<style-feature-plain> |
<style-feature-boolean> |
<style-range>

<scroll-state-in-parens> =
( <scroll-state-query> ) |
( <scroll-state-feature> ) |
<general-enclosed>

<style-feature-plain> =
<style-feature-name> : <style-feature-value>

<style-feature-boolean> =
<style-feature-name>

<style-range> =
<style-range-value> <mf-comparison> <style-range-value> |
<style-range-value> <mf-lt> <style-range-value> <mf-lt> <style-range-value> |
<style-range-value> <mf-gt> <style-range-value> <mf-gt> <style-range-value>

<style-range-value> =
<custom-property-name> |
<style-feature-value>

<mf-comparison> =
<mf-lt> |
<mf-gt> |
<mf-eq>

<mf-lt> =
'<' '='?

<mf-gt> =
'>' '='?

<mf-eq> =
'='

示例

根据容器大小设置样式

考虑以下一个带有标题和一些文本的卡片组件示例:

html
<div class="post">
  <div class="card">
    <h2>Card title</h2>
    <p>Card content</p>
  </div>
</div>

可以使用 container-type 属性创建容器上下文,在本例中,在 .post 类上使用 inline-size 值。然后,你可以使用 @container @ 规则将样式应用于宽度小于 650px 的容器中的 .card 类的元素。

css
/* A container context based on inline size */
.post {
  container-type: inline-size;
}

/* Apply styles if the container is narrower than 650px */
@container (width < 650px) {
  .card {
    width: 50%;
    background-color: lightgray;
    font-size: 1em;
  }
}

创建命名的容器上下文

给定以下 HTML 示例,它是一个带有标题和一些文本的卡片组件:

html
<div class="post">
  <div class="card">
    <h2>Card title</h2>
    <p>Card content</p>
  </div>
</div>

首先,使用 container-typecontainer-name 属性创建一个容器上下文。此声明的简写语法在 container 页面中有描述。

css
.post {
  container-type: inline-size;
  container-name: summary;
}

接下来,通过将名称添加到容器查询中来定位该容器:

css
@container summary (width >= 400px) {
  .card {
    font-size: 1.5em;
  }
}

嵌套容器查询

在一个容器查询中不能定位多个容器。但可以嵌套容器查询,效果相同。

如果名为 summary 的容器宽度大于 400px,并且其祖先容器宽度大于 800px,则以下查询求值为真并应用声明的样式:

css
@container summary (width > 400px) {
  @container (width > 800px) {
    /* <stylesheet> */
  }
}

容器样式查询

容器查询还可以评估容器元素的计算样式。容器样式查询是使用一个或多个 style() 函数表示法的 @container 查询。将样式特性组合成样式查询的布尔语法和逻辑与CSS 特性查询相同。

css
@container style(<style-feature>),
    not style(<style-feature>),
    style(<style-feature>) and style(<style-feature>),
    style(<style-feature>) or style(<style-feature>) {
  /* <stylesheet> */
}

每个 style() 的参数都是一个 <style-feature><style-feature> 是一个有效的 CSS 声明、一个 CSS 属性或一个 <custom-property-name>

css
@container style(--themeBackground),
    not style(background-color: red),
    style(color: green) and style(background-color: transparent),
    style(--themeColor: blue) or style(--themeColor: purple) {
  /* <stylesheet> */
}

如果计算值与给定属性的初始值不同,则没有值的样式特性求值为真。

如果作为 style() 函数参数传递的 <style-feature> 是一个声明,那么当该声明的值与被查询容器的该属性的计算值相同时,样式查询求值为真。否则,它解析为假。

以下容器查询检查容器元素的 --accent-color计算值是否为 blue

css
@container style(--accent-color: blue) {
  /* <stylesheet> */
}

注意:如果一个自定义属性的值为 blue,那么等效的十六进制代码 #0000ff 将不匹配,除非该属性已使用 @property 定义为颜色,以便浏览器可以正确比较计算值。

查询简写属性的样式特性,如果其每个普通属性的计算值都匹配,则为真,否则为假。例如,如果构成该简写属性的所有 12 个普通属性(border-bottom-style 等)都为真,则 @container style(border: 2px solid red) 将解析为真。

全局关键字 revertrevert-layer<style-feature> 中作为值是无效的,并导致容器样式查询为假。

滚动状态查询

有关滚动状态查询示例的完整演练,请参见使用容器滚动状态查询

规范

规范
CSS 条件规则模块第五版
# container-rule

浏览器兼容性

另见