题干与适用场景
一个卡片组件会同时出现在主内容区、侧栏和网格中。请解释 CSS 容器查询与媒体查询的区别,写出按卡片容器宽度切换布局的 CSS,并说明容器建立、查询作用域、回退和测试方案。
媒体查询根据视口或设备特征做判断;容器查询根据祖先查询容器的尺寸、样式或滚动状态做判断。GreatFrontEnd 的 CSS 面试资料直接把容器查询列为面试题,Hack Frontend 的 HTML/CSS 题单也覆盖该主题;MDN 文档说明了 container-type、@container 与容器查询单位的规范行为。本文不绑定具体公司。
面试官考察点
面试官看候选人能否先区分响应对象,再写出完整上下文。高质量回答应说明 container-type: inline-size 建立尺寸查询上下文,查询规则作用于后代而非容器本身,默认匹配最近的合格祖先,并解释为什么同一视口下不同卡片宽度需要容器查询。
还要检查候选人是否理解尺寸包含的副作用、命名容器的边界、旧浏览器回退和测试方法。只把 @media 改写成 @container,却没有建立容器或处理嵌套关系,代码无法按预期工作。
回答前需要澄清的问题
- 响应什么尺寸? 本题响应卡片分配到的内联尺寸,不响应整个视口。
- 是否需要样式或滚动状态查询? 本题只需要尺寸查询;样式查询和滚动状态查询属于可选扩展。
- 兼容范围是什么? 先确认目标浏览器;不支持容器查询时保留可用的基础布局和媒体查询回退。
- 组件边界是否嵌套? 若有嵌套卡片,使用
container-name明确应该读取哪一层。
30 秒回答框架
“媒体查询观察视口,适合页面级断点;容器查询观察组件祖先容器,适合同一组件在不同布局槽位复用。先在卡片外层设置 container-type: inline-size,再用 @container 按容器内联尺寸切换布局。查询只影响后代,默认使用最近的合格容器;复杂嵌套用 container-name。我会提供基础样式和 @supports 回退,并在固定视口下调整父容器宽度测试主区、侧栏、网格和不支持该特性的浏览器。”
分步骤深入解答
第一步:先比较响应对象和作用域
| 维度 | 媒体查询 | 容器查询 |
|---|---|---|
| 响应对象 | 视口、设备或用户偏好 | 祖先查询容器的尺寸、样式或滚动状态 |
| 典型范围 | 页面级布局 | 可复用组件内部布局 |
| 建立方式 | @media 直接读取媒体特征 | 祖先设置 container-type,后代使用 @container |
| 组件行为 | 同一视口通常共享断点 | 每个实例可按实际分配宽度响应 |
媒体查询适合导航、整页栏列和打印等页面级决策。容器查询解决的是组件不知道自己会被放入多宽的槽位:主栏和侧栏可以在同一视口下分别采用不同布局。
第二步:建立尺寸查询上下文
.card-list {
container-type: inline-size;
container-name: card-list;
}
.card {
display: grid;
gap: 0.75rem;
}
@container card-list (inline-size > 40rem) {
.card {
grid-template-columns: 8rem 1fr;
align-items: center;
}
}inline-size 建立按内联轴尺寸查询的容器,适合同时考虑不同书写模式的组件。size 会建立更强的双轴尺寸包含,只有在确实需要块轴查询时才使用。normal 不建立尺寸查询上下文。查询条件写在 @container 中,规则匹配容器的后代。
第三步:理解最近容器、命名和查询单位
未指定名称时,浏览器寻找最近的合格祖先;嵌套组件可能因此读取到错误边界。命名容器可以把意图写清楚:@container card-list (...) 只匹配名为 card-list 的容器。容器查询长度单位如 cqw、cqi 可按查询容器宽度或内联尺寸缩放,但仍应配合合理的最小值和最大值,避免小容器产生不可读文本。
查询规则不能让容器本身根据自己的查询结果改变尺寸,否则会形成反馈循环;规范通过包含和作用域限制避免这种循环。尺寸包含也可能改变自动尺寸计算,因此要检查空内容、图片未加载和高度依赖内容的情况。
第四步:设计回退和渐进增强
.card {
display: block;
}
@supports (container-type: inline-size) {
.card-list {
container-type: inline-size;
}
@container (inline-size > 40rem) {
.card {
display: grid;
grid-template-columns: 8rem 1fr;
}
}
}基础布局应在没有容器查询时仍然可读。媒体查询可以作为页面级兜底,但不能假设视口断点能准确代表侧栏或网格单元宽度。若目标浏览器不支持 @supports 所检测的能力,就停留在基础样式,不影响核心内容和操作。
第五步:用场景和边界验证
固定浏览器视口,分别把同一组件放入主栏、侧栏和两列网格,再只调整父容器宽度,观察卡片是否按容器而非视口切换。测试嵌套命名容器、不同书写模式、图片加载前后、极窄容器、动态插槽和不支持容器查询的浏览器。还要确认组件没有依赖某个页面 DOM 层级,否则复用时会静默匹配到错误容器。
可接受的实现边界
回答不必覆盖所有查询类型,但必须准确区分视口与祖先容器,并让示例具备可运行的容器上下文。若选择 size、样式查询或滚动状态查询,应说明额外的包含影响、浏览器目标与测试边界;若不确定兼容范围,应明确把基础布局作为安全默认值。
常见错误与反例
- 忘记设置
container-type:只有@container没有查询上下文,规则不会按尺寸生效。 - 把容器写成自身查询目标:查询规则只能稳定地影响后代,不能用来让容器根据自己结果循环改变尺寸。
- 把
size当作默认值:双轴包含会影响自动尺寸,组件只关心横向时优先inline-size。 - 只在大屏测试:同一视口下侧栏和主栏宽度不同,必须固定视口并调整父容器验证。
- 没有基础回退:旧浏览器中卡片可能失去布局,基础样式应先保证内容可用。
追问及应对
什么时候仍然使用媒体查询?
导航、整页栏列、打印和用户偏好等决策依赖视口或媒体特征时,媒体查询更直接。组件内部断点依赖父容器时,再使用容器查询。
inline-size 和 size 如何选择?
只按横向可用空间响应时选择 inline-size;需要同时按块轴和内联轴查询时才考虑 size,并验证自动尺寸、空内容和图片加载后的结果。
如何处理不支持容器查询的浏览器?
提供基础单列或流式布局,用 @supports (container-type: inline-size) 渐进增强;媒体查询可以补充页面级体验,但不能替代所有容器级断点。