媒体查询为什么不够用了
过去做响应式,全靠 @media:判断视口宽度,然后改样式。问题是组件的形态其实不取决于视口,而取决于它被放在多大的容器里。同一个卡片组件,放在宽栏是横排、塞进窄侧栏就得竖排,但它根本不知道自己现在占多宽——媒体查询只能看到整个屏幕。
结果就是同一套组件要为不同位置写一堆重复的断点,组件失去了“自适应性”。现代 CSS 的几个新特性,正是冲着这个痛点来的:容器查询让组件按容器尺寸适配、子网格让嵌套布局对齐、级联层让样式优先级变得可管理。
- 容器查询组件按父容器宽度变化,不再盯视口。
- 子网格子元素能直接对齐父网格的轨道。
- 级联层用 @layer 显式分层控制样式优先级。
- 渐进增强新特性按支持度优雅降级,不拖累老浏览器。
容器查询:按容器宽度适配
容器查询分两步:先给某个父元素声明它是“查询容器”,再对子元素写“当容器多宽时怎么排版”。这样组件搬来搬去,会根据当前所在容器的宽度自动切换布局,真正做到组件自包含。
/* 把卡片列表声明为查询容器 */
.card-list { container-type: inline-size; }
/* 卡片在容器够宽时横排,窄时竖排 */
@container (min-width: 480px) {
.card { display: flex; gap: 1rem; }
}
注意 container-type: inline-size 是按内联方向(通常是宽度)查询。配合 @container,以前要写在媒体查询里的那套横排竖排逻辑,现在下沉到组件内部,侧栏、主区、弹窗里放同一个组件都能自适应。
子网格:对齐父子网格
普通网格里,子元素只能在自己这一层的网格里排布;如果子元素内部又套了一层网格,两层网格的轨道对不齐,卡片之间的标题、图片、文字就会参差不齐。subgrid 让子元素直接借用父网格的轨道。
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
}
/* 子元素复用父网格的列轨道,保证全站对齐 */
.grid > .cell {
display: grid;
grid-row: span 3;
grid-template-rows: subgrid;
}
有了 subgrid,嵌套网格的行和列能和外层对齐,多卡片布局高度一致、视觉整齐,不再要靠固定高度或魔法数字去硬凑。
级联层:把优先级交给你自己
CSS 历来最大的痛是优先级打架:选择器越写越长、!important 满天飞,最后谁也说不清哪个样式会生效。级联层(@layer)让你显式给样式分“层”,层与层的优先级由你声明的顺序决定,而不是被选择器权重绑架。
@layer reset, base, components, utilities;
@layer components {
.btn { padding: .5rem 1rem; }
}
@layer utilities {
/* utilities 层最后声明,天然压过 components */
.mt-2 { margin-top: .5rem; }
}
越靠后声明的层优先级越高。配合设计系统,把 reset、基础、组件、工具类分成四层,工具类放心写、组件类不被工具类意外覆盖,再也不用靠 !important 赢。
逻辑属性与 :has 选择器
另外两个值得知道的现代特性:逻辑属性用 margin-inline-start、padding-block 这类按书写方向的属性,替代 left/right 硬编码,页面一旦换方向(如阿拉伯语从右到左)自动适配;:has() 选择器能根据父元素是否包含某个子元素来给父元素加样式,比如“当卡片里有图时给它特殊内边距”,过去要靠 JS 判断,现在一行 CSS 搞定。
/* 卡片内部有图时,取消卡片自身的上间距 */
.card:has(img) { padding-top: 0; }
/* 用逻辑属性替代硬编码左右 */
.box { margin-inline-start: 1rem; }
浏览器兼容与渐进增强
这些新特性不是一夜之间全站支持的。正确姿势是渐进增强:先用基础写法保证所有浏览器都能用,再用 @supports 给支持的浏览器叠加增强。老浏览器不认识容器查询就回退到固定布局,认识就享受自适应,功能不丢、体验分层。
@supports (container-type: inline-size) {
.card-list { container-type: inline-size; }
}
上线前用 caniuse 查支持度,对核心用户群体的老浏览器保留兜底样式。新特性是加分项,不是准入门槛。
实战清单
落地清单:
- 组件布局优先用容器查询,别再让媒体查询管到组件内部。
- 嵌套对齐用 subgrid,少写固定高度和魔法数字。
- 样式体系用 @layer 分层,甩掉 !important。
- 边距间距尽量用逻辑属性,为多语言方向做准备。
- 需要“按子元素形态调父元素”时用 :has(),能省掉 JS。
- 新特性配 @supports 渐进增强,老浏览器有兜底。
现代 CSS 的方向很明确:把布局的判断从视口还给容器、把样式的优先级还给设计者、把重复的 JS 逻辑还给 CSS 本身。用好容器查询、子网格和级联层,组件会更自包含、代码会更干净,响应式再也不是一堆硬编码断点的堆砌。