C01 现代布局与逻辑属性

2026-10-31 17:100 阅读约 12 分钟CSS

C01 现代布局与逻辑属性

摘要:媒体查询按视口宽度切换,组件换到窄栏里就失效;aspect-ratio 让高度随宽度自动确定;逻辑属性把左右换成起止,适配从右到左的书写方向。这三项共同解决「组件与容器解耦」的问题——组件只关心自己被放进多宽的容器。
关键词:容器查询,容器单位,宽高比,子网格,逻辑属性,:has

所属:frontend/css / C-高级 | 上一篇:C00-总结 | 下一篇:C02-可维护CSS与命名分层

1 引言

响应式断点绑定视口,这在整页布局中合理,在组件中不合理:同一张卡片在侧栏与主区里宽度相差三倍,却拿到同一套样式。

本文给出按容器响应的写法与三项配套能力。范围见表 1-1。

项 本文覆盖 本文不覆盖
容器查询 container-type、@container、容器单位 嵌套容器的命名冲突
尺寸控制 aspect-ratio、min()/max()、容器单位 图片裁切与对象适应(C08)
方向 margin-inline、inset-block、padding-block 双向文本混排
选择 :has() 完整选择器性能分析

2 预备知识

项 要求 核对方式
环境 本地服务器可用 浏览器能打开 localhost
文件 css-practice/modern.html 编码 UTF-8
浏览器 Chrome 130+(容器查询与 :has 已支持) 能验证查询生效
前置 A08、A07 断点与网格已掌握

3 原理与实现

3.1 从视口响应改为容器响应

容器查询把断点判断对象从视口换成祖先容器,如图 3-1 所示。

flowchart LR
    A["父容器<br/>container-type: inline-size"] --> B["组件"]
    B --> C{"@container (min-width: 30rem)"}
    C -->|"是"| D["横向布局 + 大图"]
    C -->|"否"| E["纵向布局 + 小图"]
    A2["视口变窄"] --> A

图 3-1 容器查询的判断对象

图上可见:组件只关心容器宽度,侧栏、主区、弹层里都能自动切换,不需要额外断点。

3.2 配套写法

/* 运行环境:Chrome 130+;css-practice/modern.css */
.card-wrap { container-type: inline-size; container-name: card; }

.card { display: grid; grid-template-columns: 1fr; gap: 1rem; }
.card__media { aspect-ratio: 16 / 9; background: #e2e8f0; border-radius: 0.5rem; }

@container card (min-width: 30rem) {
  .card { grid-template-columns: 12rem minmax(0, 1fr); align-items: center; }
}

.article {
  margin-inline: auto;
  padding-block: 2rem;
  max-inline-size: 42rem;
}

.article h2 { margin-block: 2rem 0.75rem; }

.form:has(input:invalid) { border-inline-start: 3px solid #b91c1c; }

.grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1rem;
}

.grid__item--wide { grid-column: span 2; }

四项能力的用途见表 3-1。

能力 写法 解决的问题
容器查询 container-type: inline-size + @container 组件在不同宽度容器内自适应
宽高比 aspect-ratio: 16 / 9 图片与占位区高度不确定
逻辑属性 margin-inline、padding-block 适配 RTL 书写方向
关系选择 :has(input:invalid) 父级根据子级状态变化
子网格(简用) grid-template-columns: subgrid 让子元素对齐父网格轨道

逻辑属性与物理属性对照见表 3-2。

物理属性 逻辑属性 说明
margin-left/right margin-inline 随书写方向翻转
margin-top/bottom margin-block 随书写模式变化
padding-left padding-inline-start 起边
width inline-size 行内方向尺寸
top/bottom inset-block 块级方向偏移
left/right inset-inline 行内方向偏移

3.3 容器单位与子网格

容器尺寸确定后,内部尺寸也可按容器比例取值,子网格让孙元素对齐父网格轨道,两者配套写法如下。

/* 运行环境:Chrome 130+;css-practice/modern.css */
.card-wrap { container-type: inline-size; container-name: card; }

.card__title {
  /* cqi = 容器行内尺寸的 1%,随容器缩放而非视口 */
  font-size: clamp(1rem, 4cqi, 1.75rem);
}

.card__meta { font-size: max(0.75rem, 2cqi); }

/* 子网格:卡片内容对齐外层网格的列轨道 */
.list { display: grid; grid-template-columns: 12rem 1fr auto; gap: 1rem; }

.list__item {
  display: grid;
  grid-column: 1 / -1;
  grid-template-columns: subgrid;   /* 继承父网格的三列定义 */
  align-items: center;
}

容器单位与视口单位对照见表 3-3。

单位 基准 用途
cqw 容器宽度 1% 需按容器缩放的内边距
cqi 容器行内尺寸 1% 卡片标题的流体字号
cqb 容器块级尺寸 1% 与容器高度挂钩的间距
cqmin/cqmax 容器长短边较小/较大者 方形容器内的比例尺寸
vw/vh 视口尺寸 整页级排版,组件内不用

表 3-3 容器单位与视口单位的基准差异

使用 subgrid 的两条前提:父级必须是网格容器,子项必须跨越多条轨道(grid-column: 1 / -1)。二者缺一时子网格退化为普通网格,列宽各自计算,不再对齐。

4 验证与讨论

  1. 打开页面,把卡片容器宽度从 20rem 调到 40rem,确认布局从纵向变横向,标题字号随容器同步变化。
  2. 给 html 加 dir="rtl",确认文字与间距整体翻转,物理边距写法会失效。
  3. 在输入框输入非法值,确认卡片左侧出现红色竖条(:has 生效)。
  4. 把 aspect-ratio 删掉,观察占位区高度塌陷与布局抖动。
检查项 预期结果 说明
容器响应 容器变宽时卡片转横向 @container
方向适配 dir="rtl" 后间距翻转 逻辑属性
关系选择 子元素非法时父级变色 :has()
占位稳定 图片加载前后高度一致 aspect-ratio

讨论与局限。 容器查询需要祖先声明 container-type,且该属性会创建包含块,可能影响绝对定位子元素。另 :has() 在高频变动场景下有一定成本,避免用于每帧变化的选择器。

5 常见问题

现象 原因 处理
容器查询不生效 祖先未设置 container-type 给直接父级加 inline-size
卡片高度随图片跳动 未设置宽高比 补 aspect-ratio
RTL 下间距错位 使用物理属性 改逻辑属性
:has() 无效果 选择器写错或浏览器版本过低 简化选择器,核对支持度
子网格未对齐 父级不是网格 subgrid 只能用于网格子项

6 结论

序号 结论 依据
1 组件按容器宽度响应,不按视口 图 3-1
2 占位区一律给宽高比 表 3-1
3 涉及方向的距离用逻辑属性 表 3-2
4 :has() 用于父级随子级状态变化 表 3-1

参考文献

[1] MDN Web Docs · CSS 容器查询,https://developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_containment/Container_queries(访问于 2026-10-31)
[2] CSS Logical Properties and Values Level 1,W3C,https://www.w3.org/TR/css-logical-1/(访问于 2026-10-31)

返回文章列表

评论 0

0/2000

还没有评论,快来抢沙发吧~