13响应式与媒体查询
一套 HTML + 一份 CSS,如何同时在手机、平板、桌面三端都好看?
答案就是响应式(Responsive)三支柱:媒体查询 @media(按视口条件切换样式)、
流式单位(% / vw / clamp() 让尺寸随屏幕呼吸)、
移动优先(先做小屏,再 min-width 渐进增强)。
今天把三大支柱一次学完——再到第 14 课学 Flex / Grid 布局。
一、媒体查询 @media:CSS 的 if 判断
媒体查询的语法极简——@media (条件) { 样式 },
条件成立才生效,不成立就当不存在。和 JS 的 if 一个意思。
最常用条件是「视口宽度」,进阶还有横竖屏、系统主题、指针精度等。
| 媒体特性 | 常用值 | 判断什么 | 典型场景 |
|---|---|---|---|
| min-width / max-width | 768px 等长度 | 视口宽度阈值 | 断点切换布局,99% 场景都靠它 |
| orientation | portrait / landscape | 横屏还是竖屏 | 视频全屏、游戏场景 |
| prefers-color-scheme | light / dark | 系统主题 | 暗色模式适配 |
| hover | hover / none | 是否有悬停能力 | 手机 hover:none,按钮可隐藏悬浮菜单 |
| pointer | fine / coarse / none | 指针精度 | coarse=手指(增大点击区)、fine=鼠标 |
| prefers-reduced-motion | reduce / no-preference | 用户是否要减少动效 | 关掉过场动画,无障碍标配 |
800px 改成 500px 看阈值变化;拖动浏览器边缘(或 DevTools Toggle Device)实际看效果min-width(移动优先),而不是 max-width(桌面优先)。
原因——同一份样式,写 min-width 时只需要从最小屏往大覆盖,写 max-width 时要不停覆盖桌面样式,
后者会陷入「补丁叠补丁」的混乱。二、断点选择:按内容而非设备
「断点」就是媒体查询的临界宽度。没有标准答案—— 业界常见的 768 / 1024 只是历史经验,真正决定断点的是你自己的内容什么时候开始变形。 三个主流框架的参考体系如下:
| 设备类型 | Bootstrap 5 | Tailwind 3 | Material 3 | 常见内容临界 |
|---|---|---|---|---|
| 手机 | < 576px | < 640px | 0 ~ 599dp | 单列布局、所有内容垂直堆叠 |
| 大手机 / 小平板 | ≥ 576px | ≥ 640px | 600 ~ 839dp | 可放两列、字号放大 |
| 平板 | ≥ 768px | ≥ 768px | 840 ~ 1199dp | 多列布局、侧边栏登场 |
| 桌面 | ≥ 992px | ≥ 1024px | 1200 ~ 1599dp | 完整布局、最大宽度封顶 |
| 大屏 | ≥ 1200px | ≥ 1280px | ≥ 1600dp | 居中留白、内容不超过 1200px |
100vh 做全屏背景,会出现「地址栏收起时多出一段空白」。
现代方案用 100dvh(dynamic viewport height)替代——它会跟随地址栏动态调整。三、流式单位:% / vw / vh / vmin / vmax / clamp()
写死 px 的布局一换屏就崩。流式单位让尺寸跟随视口呼吸——
视口有多大,元素就多大。六种视口单位各司其职:
| 单位 | 含义 | 典型用法 | 注意事项 |
|---|---|---|---|
| % | 相对父元素 | 子元素宽度 50% | 高度 % 要父元素有显式高度才生效 |
| vw | 视口宽度的 1% | 全屏 banner、font-size: 4vw | 小屏会缩得太小、大屏会放得太大 |
| vh | 视口高度的 1% | 全屏背景、移动端首屏 | iOS Safari 用 dvh 替代 |
| vmin | 视口宽高较小者的 1% | 横竖屏都正方形的元素 | 游戏 UI、保持比例的按钮 |
| vmax | 视口宽高较大者的 1% | 横屏特别宽的设备 | 桌面端很少用 |
| clamp(MIN, FLUID, MAX) | 夹在三值之间 | 流体字号 clamp(1rem, 2vw, 2rem) | 现代字号首选,一行顶十行 |
0.5rem + 2vw 的意思是——浏览器宽度为 0 时字号 0.5rem,
每增加 1vw 字号增加 0.02rem(因为 2vw = 0.02rem × 浏览器宽度 / 1),
最后用 clamp 夹出上下限。改「斜率」就能改响应速度。四、移动优先 vs 桌面优先
「移动优先」(Mobile First)= 先写最小屏的样式,再用 min-width 渐进增强;
「桌面优先」则反过来,先写桌面,再用 max-width 优雅降级。
现代工程统一推荐移动优先——代码更少、维护更容易、性能更好。
移动优先(推荐)
min-width 渐进增强@media (min-width: 768px) {
.card { padding: 24px; }
}
桌面优先(不推荐)
max-width 覆盖补丁@media (max-width: 768px) {
.card { padding: 12px; }
}
/* 改一次桌面要同步改多处 */
min-width 往上加,max-width 几乎不用;
③ 改一次样式只改一个地方,不会牵一发动全身。五、图片自适应:max-width: 100% + srcset
一张 800px 的大图塞进 300px 的手机容器,要么溢出、要么被裁——都是灾难。
两行 CSS 解决:max-width: 100%; height: auto,
图片永不超出容器,高度按比例自动算。
配合 srcset 还能给 Retina 屏喂高清图,普通屏喂小图省流量。
object-fit: cover + object-position 让图片「裁剪对齐」。
详见「CSS 基础」第 4 课《背景与边框》里 object-fit 详解——同一个属性既能用给背景,也能用给 <img>。六、容器查询 @container 横向对比(呼应第 12 课)
媒体查询是「视口多宽我就怎么排」;
容器查询(@container)是「我爹多宽我就怎么排」。
现代组件化开发,容器查询才是更优解——同一个卡片组件,
放在侧边栏和主内容区能各自独立适配,不再依赖视口。
| 维度 | @media 媒体查询 | @container 容器查询 |
|---|---|---|
| 判断依据 | 视口(浏览器)宽度 | 最近祖先容器的宽度 |
| 语法 | @media (min-width: 768px) | @container (min-width: 400px) |
| 前置声明 | 不需要 | 父容器需写 container-type: inline-size |
| 适用场景 | 整页布局(导航、栅格) | 可复用组件(卡片、徽章) |
| 兼容性 | 全浏览器支持 | Chrome 105+ / Safari 16+ / Firefox 110+ |
窄容器(200px)→ 竖排
宽容器(360px)→ 横排
@media(比如整页导航、底部页脚);
判断的是「父容器维度」就用 @container(比如同一张卡片要复用进侧边栏 / 主区 / 弹窗)。
一个项目通常两者混用,不冲突。七、暗色模式适配:prefers-color-scheme
系统设置成「深色」时,网页还在用亮白背景——体验割裂。
prefers-color-scheme 让 CSS 自动跟随:
@media (prefers-color-scheme: dark) { ... } 一段就搞定。
配合CSS 变量实现「一份定义、两套变量」——切换主题只换变量值,
不必复制粘贴一整份样式。
prefers-color-scheme: light
背景 #FDF9F4 · 文字 #6B6053 · 边 #C9B995
prefers-color-scheme: dark
背景 #2A2218 · 文字 #E8DDC9 · 边 #4E2A18
prefers-color-scheme——
用户可能在系统亮色下也想用网站的暗色版;高级站点会提供「手动切换开关」,用 JS 加 class 覆盖系统偏好。
② 暗色模式别用纯黑 #000——纯黑 + 纯白对比度太刺眼,
推荐 #1A1A1A ~ #2A2218 这种「暗灰」做背景,#E8DDC9 这种「米白」做文字。@media (prefers-color-scheme),还要在 <head> 里加
<meta name="color-scheme" content="light dark">——
告诉浏览器「这个页面支持亮 + 暗主题」,原生滚动条、表单控件才会自动反色,否则手机浏览器会把表单染成惨白一片。八、本章小结
- 媒体查询
@media (条件) { ... }是响应式的灵魂——按视口、横竖屏、系统主题等条件切换样式。 - 断点按内容决定而非按设备;现代推荐
min-width(移动优先)。 - 流式单位家族:
%/vw/vh/vmin/vmax,最实用的是clamp(MIN, FLUID, MAX)流体公式。 - 图片自适应两行 CSS 标配:
img { max-width: 100%; height: auto; },配合srcset给 Retina 屏喂高清图。 @container容器查询让组件知道自己父容器多宽——比媒体查询更适合可复用组件。- 暗色模式三件套:
@media (prefers-color-scheme: dark)+ CSS 变量 +<meta name="color-scheme">。 - 全站响应式开发流:移动优先 + 流式单位 + 容器查询组件 + 图片自适应 + 暗色模式。
min-width;
② 用 clamp() 给主标题做流体字号(试试 clamp(1.5rem, 1rem + 2vw, 3rem));
③ 给所有 <img> 加 max-width: 100%; height: auto; 让图片永不溢出;
④ 把颜色都改成 CSS 变量,加一段 @media (prefers-color-scheme: dark) 支持暗色模式。
改完拿 DevTools 切到手机 / 平板 / 桌面三种宽度验证。