CSS 媒体查询只在设备或浏览器满足某个条件时才应用一组样式,例如视口达到最小宽度、处于横屏方向,或使用深色配色方案。@media (min-width: 48rem) { ... } 的意思是“当视口宽度至少为 48rem 时使用这些规则”。正是媒体查询让同一个页面能在手机、平板和桌面之间切换布局。
基本语法
@media (min-width: 768px) {
.sidebar { display: block; }
}
媒体查询由三个可选部分组成:
- 媒体类型:
screen、print或all(默认值) - 一个或多个写在括号里的媒体特性,例如
(min-width: 768px)或(orientation: landscape) - 用来组合它们的逻辑运算符:
and、,(或)和not
@media screen and (min-width: 768px) and (orientation: landscape) { ... }
@media (max-width: 480px), (orientation: portrait) { ... }
@media not print { ... }
也可以把媒体查询应用到整个样式表:<link rel="stylesheet" href="print.css" media="print">。
min-width 与 max-width
min-width 表示“不小于这个宽度”,max-width 表示“不大于这个宽度”。你选择的方向决定了其余 CSS 的写法。
- 移动优先(推荐):基础样式面向手机,再用
min-width查询为更大的屏幕增加布局。见移动优先设计。 - 桌面优先:基础样式面向桌面,再用
max-width查询为小屏幕撤销部分样式。
/* Mobile first */
.nav { flex-direction: column; }
@media (min-width: 48rem) {
.nav { flex-direction: row; }
}
在同一个项目里混用两种方向,很容易出现范围重叠或断档。选定一种,另一种只用于少量例外情况。
现代的范围语法
Media Queries Level 4 引入了比较运算符,可读性更好,也能避免差一像素的错误:
@media (width >= 48rem) { ... }
@media (40rem <= width < 64rem) { ... }
所有当前主流浏览器都支持范围语法(Chrome 和 Edge 从 104 版起,Firefox 从 63 版起,Safari 从 16.4 版起)。如果需要兼容旧版 Safari,就继续使用 min-width 和 max-width,或者交给构建工具转换。
注意 (width < 768px) 和 (max-width: 767px) 并不完全相同:前者也会匹配 767.5px,这种宽度在像素比为小数的屏幕上确实会出现。
移动端媒体查询:常见示例
小屏幕上让列纵向堆叠:
.grid { display: grid; gap: 1rem; }
@media (min-width: 40rem) {
.grid { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 64rem) {
.grid { grid-template-columns: repeat(4, 1fr); }
}
手机上使用更小的间距:
.section { padding: 2rem 1rem; }
@media (min-width: 64rem) {
.section { padding: 6rem 2rem; }
}
高度很小的横屏手机:
@media (orientation: landscape) and (max-height: 30rem) {
.site-header { position: static; }
}
最后这个例子经常被忽略。竖屏时没问题的吸顶头部,横屏时可能会占掉三分之一的屏幕。
具体该用哪些宽度是另一个问题,见响应式断点指南。
宽度以外的媒体特性
| 特性 | 示例 | 用途 |
|---|---|---|
orientation |
(orientation: landscape) |
手机或平板旋转时调整布局 |
hover |
(hover: hover) |
只在能悬停的设备上启用悬停效果 |
pointer |
(pointer: coarse) |
为触屏设备提供更大的点击区域 |
prefers-color-scheme |
(prefers-color-scheme: dark) |
深色主题 |
prefers-reduced-motion |
(prefers-reduced-motion: reduce) |
关闭动画 |
resolution |
(min-resolution: 2dppx) |
在 CSS 背景中使用高清图片 |
display-mode |
(display-mode: standalone) |
为已安装的 Web 应用设置样式 |
hover 和 pointer 比看上去更重要。触屏笔记本或使用桌面宽度布局的平板同样无法悬停,所以只靠悬停展开的菜单要用 @media (hover: hover) 包起来。
断点用 rem 或 em
用 rem 或 em 写的媒体查询会跟随用户在浏览器中设置的字号。如果有人把默认字号从 16px 调到 24px,48rem 的断点就会从 768px 移到 1152px,文字变大时布局会切换到更宽松的版本。像素断点会忽略这个设置。在媒体查询中,rem 和 em 都以浏览器的初始字号为基准,而不是你在 CSS 中给 html 设置的字号。
媒体查询与容器查询
媒体查询响应视口,容器查询响应元素所在容器的尺寸:
.card-wrap { container-type: inline-size; }
@container (min-width: 30rem) {
.card { display: flex; }
}
页面级布局(分栏、导航)用媒体查询,会出现在不同宽度位置的组件用容器查询。
常见错误
- 缺少 viewport meta 标签。 没有它,手机会报告约 980px 的视口,你的移动端媒体查询永远不会生效。见 viewport meta 标签详解。
- 范围重叠,例如
max-width: 768px和min-width: 768px在正好 768px 时都会匹配。 - 媒体查询写在基础规则之前。 优先级相同时,后写的规则胜出,所以查询必须写在它要覆盖的规则之后。
- 只靠缩放窗口来测试。 桌面浏览器无法缩小到大多数手机的宽度。请使用设备模式,或能设置真实视口和 User Agent 的 Mobile View Extension,并参考如何测试响应式设计。
常见问题
手机用的媒体查询怎么写?
没有一个专门针对手机的查询。移动优先的 CSS 把手机当作默认情况,不加任何查询,再为大屏幕添加 @media (min-width: 40rem) 之类的查询。如果只想针对小屏幕,可以用 @media (max-width: 39.99rem) 或 (width < 40rem)。
媒体查询应该用 px、em 还是 rem?
从无障碍角度看,rem 或 em 更好,因为断点会随用户的字号设置缩放。px 也能用,但会忽略这个设置。
媒体查询应该放在 CSS 的什么位置?
可以放在它所修改的组件旁边,也可以集中放在文件末尾。放在组件旁边更便于维护,但无论哪种方式,都必须位于基础规则之后。