3、媒体查询入门:媒体类型、媒体特性、逻辑操作符、断点策略
媒体查询(Media Queries),说白了就是让 CSS 学会「看人下菜碟」。
你写一套样式,它能在手机上是竖排布局,到了平板变成两栏,到了桌面变成三栏。这一切的核心,就是 @media 这个规则。
我记得刚入行那会儿,做响应式全靠 JS 判断窗口宽度,然后动态加载不同的 CSS 文件。那叫一个痛苦。后来 CSS3 把媒体查询标准化了,前端适配才真正有了「正规军」。
3.1 媒体类型:你适配的是什么设备?
媒体类型是最早的适配手段。它告诉浏览器:我这套样式是写给哪种设备看的。
| 媒体类型 | 说明 | 实际使用频率 |
|---|---|---|
all |
所有设备(默认值) | 极高 |
screen |
电脑屏幕、手机、平板等 | 极高 |
print |
打印机或打印预览 | 中等 |
speech |
屏幕阅读器等语音设备 | 低 |
screen 和 all。打印样式单独写一个 @media print 就够了。至于 speech,说实话我做了这么多年项目,几乎没用过。
/* 基础写法 */
@media screen {
body {
font-size: 16px;
}
}
/* 打印样式:隐藏导航和广告 */
@media print {
.nav,
.sidebar,
.ad-banner {
display: none;
}
body {
font-size: 12pt;
}
}
3.2 媒体特性:精确控制适配条件
媒体类型太粗了。你没法区分「这是个手机还是个平板」。所以我们需要媒体特性(Media Features)。
最常用的就是 width 和 height,但实际项目中我几乎只用 min-width 和 max-width。为什么?因为设备宽度千差万别,用精确值去匹配根本不现实。
min-width 做「向上兼容」,用 max-width 做「向下兼容」。不要用精确的 width: 375px 去匹配 iPhone。
除了宽高,还有几个特性值得关注:
orientation:横屏(landscape)还是竖屏(portrait)。我在做视频类 App 的 H5 页面时,经常用这个特性来调整播放器的布局。resolution:屏幕分辨率(dpi/dppx)。用来区分普通屏和 Retina 屏,加载不同精度的图片。hover:设备是否支持悬停。触摸设备不支持:hover,这个特性可以用来优化交互。pointer:指点设备的精度(fine/coarse)。手机是 coarse,鼠标是 fine。
/* 横屏时放大字体 */
@media screen and (orientation: landscape) {
body {
font-size: 18px;
}
}
/* Retina 屏加载 2x 图片 */
@media screen and (min-resolution: 2dppx) {
.logo {
background-image: url('logo@2x.png');
}
}
/* 触摸设备去掉 hover 效果 */
@media (hover: none) {
.button:hover {
background-color: initial;
}
}
resolution 的单位不支持 dppx,只认 dpi。所以稳妥的做法是同时写两个单位做 fallback。
3.3 逻辑操作符:组合你的适配条件
单个条件不够用?那就用逻辑操作符把它们组合起来。
| 操作符 | 含义 | 示例 |
|---|---|---|
and |
与(所有条件都满足) | @media screen and (min-width: 768px) |
,(逗号) |
或(满足任一条件) | @media (max-width: 600px), (orientation: portrait) |
not |
非(取反) | @media not print |
only |
仅(防止旧浏览器解析) | @media only screen |
你想想看,and 和逗号是最常用的。我个人的写法习惯是:
- 多个条件必须同时满足 → 用
and - 多个条件满足任意一个即可 → 用逗号
- 需要排除某种设备 → 用
not
/* 屏幕设备 + 宽度在 768px 到 1024px 之间 */
@media screen and (min-width: 768px) and (max-width: 1024px) {
.container {
width: 90%;
}
}
/* 手机竖屏 或 平板横屏 */
@media (max-width: 480px), (min-width: 768px) and (orientation: landscape) {
.menu {
display: block;
}
}
/* 排除打印设备 */
@media not print {
.header {
position: sticky;
top: 0;
}
}
only 操作符在现在基本用不到了。它是用来让不支持媒体查询的旧浏览器忽略整个规则的。现在谁还用 IE8 呢?我反正是直接省略。
3.4 断点策略:怎么选断点?
断点(Breakpoint)是媒体查询里最让人纠结的事。选多了,维护成本高;选少了,适配效果差。
我见过两种主流策略:
策略一:以设备为基准
直接拿主流设备的宽度当断点。比如 iPhone 的 375px、iPad 的 768px、桌面 1024px。
- 优点:简单粗暴,容易理解
- 缺点:设备更新太快,今天 iPhone 13 是 390px,明天 iPhone 14 就变 430px 了,你改不改?
策略二:以内容为基准
不管设备长什么样,只关注你的布局在什么宽度下会「崩掉」。在那个临界点设置断点。
- 优点:一劳永逸,设备怎么变都不怕
- 缺点:需要反复调试,前期工作量大
下面是我个人常用的断点体系,供你参考:
/* 手机:默认样式(0 - 575px) */
/* 不用写媒体查询,直接写基础样式 */
/* 大屏手机/小平板:576px 起 */
@media (min-width: 576px) {
...
}
/* 平板:768px 起 */
@media (min-width: 768px) {
...
}
/* 小桌面:992px 起 */
@media (min-width: 992px) {
...
}
/* 大桌面:1200px 起 */
@media (min-width: 1200px) {
...
}
/* 超大屏:1400px 起 */
@media (min-width: 1400px) {
...
}
3.5 知识体系总览
下面这张图把媒体查询的核心知识点串起来了。你可以把它当作一个快速索引。
3.6 写在最后
媒体查询不难,但它是整个设备端适配的基石。你后面学到的 rem、vw、flex、grid,最终都要和媒体查询配合使用。
嗯,这里要注意一点:别一上来就写一堆 @media。先写基础样式(手机优先),再逐步用 min-width 往上叠加。这样代码更干净,也更容易维护。
我个人习惯把媒体查询写在对应选择器的附近,而不是单独放在文件末尾。这样改一个组件的时候,不用上下翻找,效率高很多。