4、媒体查询进阶:移动优先与桌面优先策略、组合查询、常用断点库
媒体查询这东西,很多人觉得就是写几个 @media 完事。但实际项目里,断点怎么定、查询怎么写、优先策略怎么选,处处都是坑。今天我把这几年踩过的坑和总结的经验,一次性说清楚。
4.1 两种策略:移动优先 vs 桌面优先
先问个问题:你的页面是先写手机版,还是先写电脑版?
这决定了你用 min-width 还是 max-width。说白了,就是从小屏往上写,还是从大屏往下写。
移动优先(Mobile First)
我个人习惯用移动优先。原因很简单:手机用户多,而且从小屏往大屏写,逻辑更顺。
/* 基础样式:手机端 */
.container {
display: flex;
flex-direction: column;
padding: 16px;
}
/* 平板及以上 */
@media (min-width: 768px) {
.container {
flex-direction: row;
padding: 24px;
}
}
/* 桌面 */
@media (min-width: 1024px) {
.container {
max-width: 1200px;
margin: 0 auto;
}
}
你看,默认就是手机样式,然后一层层往上加。这样写出来的 CSS,基础样式就是移动端的,不会出现「手机端要覆盖桌面端样式」的尴尬。
桌面优先(Desktop First)
有些项目,比如后台管理系统、数据大屏,用户基本都在大屏上操作。这时候桌面优先更合理。
/* 基础样式:桌面端 */
.dashboard {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 20px;
}
/* 平板 */
@media (max-width: 1024px) {
.dashboard {
grid-template-columns: repeat(2, 1fr);
}
}
/* 手机 */
@media (max-width: 768px) {
.dashboard {
grid-template-columns: 1fr;
}
}
嗯,这里要注意:桌面优先用的是 max-width,意思是「小于这个宽度时生效」。所以写的时候要从大往小写,否则后面的规则会覆盖前面的。
| 对比项 | 移动优先 | 桌面优先 |
|---|---|---|
| 关键词 | min-width | max-width |
| 默认样式 | 手机端 | 桌面端 |
| 适用场景 | 面向消费者的网站 | 后台、大屏、工具类 |
| 代码量 | 通常更少 | 需要更多覆盖 |
| 维护难度 | 低 | 中 |
我的建议:新项目默认用移动优先。除非你确定 80% 以上的用户都在桌面端,否则别选桌面优先。我曾经在一个电商项目里用了桌面优先,结果手机端样式改了三轮才搞定。
4.2 组合查询:不只是宽度
很多人以为媒体查询只能查屏幕宽度。其实它能查的东西多着呢。
逻辑运算符
/* and:同时满足 */
@media (min-width: 768px) and (max-width: 1024px) {
/* 平板竖屏 */
}
/* or(用逗号):满足其一 */
@media (max-width: 480px), (orientation: landscape) {
/* 小屏手机 或 横屏 */
}
/* not:排除 */
@media not all and (pointer: coarse) {
/* 排除触屏设备 */
}
常用媒体特性
| 特性 | 说明 | 示例值 |
|---|---|---|
| width / height | 视口宽高 | 768px |
| orientation | 横竖屏 | portrait / landscape |
| aspect-ratio | 宽高比 | 16/9 |
| resolution | 分辨率 | 2dppx |
| pointer | 指针精度 | fine / coarse |
| hover | 是否支持悬停 | hover / none |
实战案例:我在做一个地图项目时,用
pointer: coarse 判断触屏设备,给按钮加了更大的点击区域。桌面端保持正常大小,移动端自动放大。一行代码解决触屏适配问题。
组合查询实战
/* 平板横屏 + 高分辨率 */
@media (min-width: 1024px) and (orientation: landscape) and (min-resolution: 2dppx) {
.map {
background-image: url('map@2x.png');
}
}
/* 可悬停 + 精细指针(鼠标) */
@media (hover: hover) and (pointer: fine) {
.card:hover {
transform: translateY(-4px);
box-shadow: 0 8px 24px rgba(0,0,0,0.12);
}
}
/* 触屏设备 + 竖屏 */
@media (pointer: coarse) and (orientation: portrait) {
.nav {
position: fixed;
bottom: 0;
width: 100%;
}
}
你想想看,如果只用宽度判断,你能区分出「带鼠标的平板」和「触屏平板」吗?不能。但 pointer 和 hover 可以。
4.3 常用断点库
断点怎么定?我见过有人拍脑袋写 600px、900px、1200px。结果到真机上一测,iPad 横屏显示不对,iPhone 14 Pro Max 又出问题。
下面是我在多个项目中沉淀下来的断点库,直接拿去用。
标准断点(移动优先)
/* 手机:默认 */
/* 大屏手机 */
@media (min-width: 480px) { }
/* 平板竖屏 */
@media (min-width: 768px) { }
/* 平板横屏 / 小桌面 */
@media (min-width: 1024px) { }
/* 桌面 */
@media (min-width: 1280px) { }
/* 大桌面 */
@media (min-width: 1440px) { }
/* 超大屏 */
@media (min-width: 1920px) { }
标准断点(桌面优先)
/* 超大屏:默认 */
/* 大桌面 */
@media (max-width: 1920px) { }
/* 桌面 */
@media (max-width: 1440px) { }
/* 小桌面 */
@media (max-width: 1280px) { }
/* 平板横屏 */
@media (max-width: 1024px) { }
/* 平板竖屏 */
@media (max-width: 768px) { }
/* 大屏手机 */
@media (max-width: 480px) { }
设备特定断点
| 设备 | 宽度 | 备注 |
|---|---|---|
| iPhone SE | 375px | 小屏手机基准 |
| iPhone 14 Pro Max | 430px | 大屏手机基准 |
| iPad mini | 744px | 小平板竖屏 |
| iPad Pro 11" | 834px | 标准平板竖屏 |
| iPad Pro 12.9" | 1024px | 平板横屏边界 |
| MacBook Air 13" | 1280px | 小桌面基准 |
| MacBook Pro 16" | 1512px | 标准桌面基准 |
避坑指南:我曾经直接拿 iPhone 的物理像素(如 1170px)写断点,结果在真机上完全不对。记住:媒体查询用的是 CSS 像素,不是物理像素。iPhone 14 Pro Max 的 CSS 宽度是 430px,不是 1290px。
4.4 知识体系图
下面这张图把媒体查询的核心知识点串起来了。你可以把它当作复习提纲。
4.5 实战建议
最后说几个我踩过的坑,你写代码时注意避开。
- 别用太多断点。3-5 个就够了。断点越多,测试成本越高,维护越痛苦。
- 断点值用变量。Sass 或 CSS 自定义属性都行。别在代码里到处写死 768、1024。
- 真机测试不可少。Chrome 模拟器再准,也不如拿真机划两下。尤其是触屏交互,模拟器永远模拟不出真实手感。
- 别忘了打印样式。
@media print很多人不写,但用户真要打印时,体验会很差。
我的习惯:项目初期先定好断点变量,写在全局样式文件里。然后所有组件都引用这些变量。这样后期改断点,改一个地方就行。我曾经在一个项目里改了三次断点,就是因为前期没定好,后期到处改,改到怀疑人生。