← 全部文章

CSS 媒体查询详解:附移动端示例

CSS 媒体查询详解:语法、min-width 与 max-width、范围语法、适用于移动端、深色模式和触屏的媒体特性,以及常见错误。

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; }
}

页面级布局(分栏、导航)用媒体查询,会出现在不同宽度位置的组件用容器查询。

常见错误

  1. 缺少 viewport meta 标签。 没有它,手机会报告约 980px 的视口,你的移动端媒体查询永远不会生效。见 viewport meta 标签详解。
  2. 范围重叠,例如 max-width: 768px 和 min-width: 768px 在正好 768px 时都会匹配。
  3. 媒体查询写在基础规则之前。 优先级相同时,后写的规则胜出,所以查询必须写在它要覆盖的规则之后。
  4. 只靠缩放窗口来测试。 桌面浏览器无法缩小到大多数手机的宽度。请使用设备模式,或能设置真实视口和 User Agent 的 Mobile View Extension,并参考如何测试响应式设计。

常见问题

手机用的媒体查询怎么写?

没有一个专门针对手机的查询。移动优先的 CSS 把手机当作默认情况,不加任何查询,再为大屏幕添加 @media (min-width: 40rem) 之类的查询。如果只想针对小屏幕,可以用 @media (max-width: 39.99rem) 或 (width < 40rem)。

媒体查询应该用 px、em 还是 rem?

从无障碍角度看,rem 或 em 更好,因为断点会随用户的字号设置缩放。px 也能用,但会忽略这个设置。

媒体查询应该放在 CSS 的什么位置?

可以放在它所修改的组件旁边,也可以集中放在文件末尾。放在组件旁边更便于维护,但无论哪种方式,都必须位于基础规则之后。

用手机视图查看你的下一个网站。

添加扩展,在你正在使用的标签页中直接打开设备预览。