现代网站需要在手机、平板、笔记本、大屏显示器等各种设备上良好呈现。响应式设计让同一份 HTML 和 CSS 能够自动适配不同屏幕尺寸,提供一致的用户体验。
视口设置#
响应式设计的第一步是正确设置视口:
<meta name="viewport" content="width=device-width, initial-scale=1" />这告诉浏览器:
width=device-width:视口宽度等于设备宽度initial-scale=1:初始缩放比例为 1
没有这个设置,移动设备会用桌面宽度渲染页面然后缩小显示。
媒体查询#
基本语法#
@media (条件) { /* 满足条件时应用的样式 */}宽度查询#
/* 视口宽度 >= 768px 时应用 */@media (min-width: 768px) { .container { max-width: 720px; }}
/* 视口宽度 <= 767px 时应用 */@media (max-width: 767px) { .sidebar { display: none; }}
/* 宽度在 768px 到 1023px 之间 */@media (min-width: 768px) and (max-width: 1023px) { .card { width: 50%; }}现代范围语法#
CSS Media Queries Level 4 引入了更直观的范围语法:
/* 等效于 min-width: 768px */@media (width >= 768px) { /* ... */}
/* 等效于 max-width: 767px */@media (width < 768px) { /* ... */}
/* 范围查询 */@media (768px <= width < 1024px) { /* ... */}逻辑运算符#
/* and:同时满足 */@media (min-width: 768px) and (orientation: landscape) { /* ... */}
/* or(逗号):满足任一 */@media (max-width: 600px), (orientation: portrait) { /* ... */}
/* not:取反 */@media not print { /* ... */}其他媒体特性#
/* 屏幕方向 */@media (orientation: portrait) { /* 竖屏 */}@media (orientation: landscape) { /* 横屏 */}
/* 高度查询 */@media (min-height: 600px) { /* ... */}
/* 分辨率 */@media (min-resolution: 2dppx) { /* Retina 屏幕 */}
/* 悬停能力 */@media (hover: hover) { /* 设备支持悬停(如鼠标) */}@media (hover: none) { /* 不支持悬停(如触屏) */}
/* 指针精度 */@media (pointer: fine) { /* 精确指针(鼠标) */}@media (pointer: coarse) { /* 粗略指针(触屏) */}
/* 颜色方案 */@media (prefers-color-scheme: dark) { /* 用户偏好深色模式 */}@media (prefers-reduced-motion: reduce) { /* 用户偏好减少动画 */}断点策略#
常用断点#
/* 手机 */@media (max-width: 639px) {}
/* 平板 */@media (min-width: 640px) and (max-width: 1023px) {}
/* 桌面 */@media (min-width: 1024px) {}
/* 大屏 */@media (min-width: 1280px) {}常见框架的断点值:
| 断点 | TailwindCSS | Bootstrap |
|---|---|---|
| sm | 640px | 576px |
| md | 768px | 768px |
| lg | 1024px | 992px |
| xl | 1280px | 1200px |
| 2xl | 1536px | 1400px |
移动优先 vs 桌面优先#
移动优先(推荐):
/* 基础样式(移动端) */.card { padding: 1rem;}
/* 逐步增强 */@media (min-width: 768px) { .card { padding: 1.5rem; }}
@media (min-width: 1024px) { .card { padding: 2rem; }}桌面优先:
/* 基础样式(桌面端) */.card { padding: 2rem;}
/* 逐步适配 */@media (max-width: 1023px) { .card { padding: 1.5rem; }}
@media (max-width: 767px) { .card { padding: 1rem; }}🎯 为什么推荐移动优先?
- 移动端样式通常更简单,便于扩展
- 符合渐进增强原则
- 移动设备性能有限,先加载基础样式更高效
响应式单位#
相对单位#
/* em:相对于元素的 font-size */.text { font-size: 1em; /* 继承父元素字号 */ padding: 1em; /* 相对于自身字号 */}
/* rem:相对于根元素(html)的 font-size */.text { font-size: 1.5rem; /* 默认 24px(16px × 1.5) */}
/* %:相对于父元素 */.child { width: 50%;}视口单位#
.hero { height: 100vh; /* 视口高度的 100% */ width: 100vw; /* 视口宽度的 100% */}
.sidebar { width: 25vw; /* 视口宽度的 25% */ min-width: 200px; max-width: 300px;}🔶 100vh 在移动端可能有问题(浏览器地址栏影响),使用 dvh:
.hero { height: 100dvh; /* 动态视口高度,考虑地址栏 */}新的视口单位:
svh/svw:小视口(地址栏展开)lvh/lvw:大视口(地址栏收起)dvh/dvw:动态视口(自动适应)
clamp() 函数#
在范围内响应式调整:
.title { /* clamp(最小值, 首选值, 最大值) */ font-size: clamp(1.5rem, 4vw, 3rem); /* 最小 1.5rem,最大 3rem,中间根据 4vw 计算 */}
.container { width: clamp(320px, 90%, 1200px);}响应式图片#
max-width 自适应#
img { max-width: 100%; height: auto;}srcset 和 sizes#
<img src="image-800.jpg" srcset="image-400.jpg 400w, image-800.jpg 800w, image-1200.jpg 1200w" sizes="(max-width: 600px) 100vw, (max-width: 1000px) 50vw, 400px" alt="响应式图片"/>picture 元素#
<picture> <source media="(min-width: 1024px)" srcset="desktop.jpg" /> <source media="(min-width: 768px)" srcset="tablet.jpg" /> <img src="mobile.jpg" alt="响应式图片" /></picture>object-fit#
.cover-image { width: 100%; height: 300px; object-fit: cover; /* 保持比例裁剪 */ object-position: center;}响应式排版#
流体字号#
html { font-size: clamp(14px, 1vw + 10px, 18px);}
h1 { font-size: clamp(2rem, 5vw, 4rem);}响应式行宽#
.article { max-width: 65ch; /* 约 65 个字符宽度 */ padding-inline: 1rem;}响应式行高#
p { line-height: calc(1.5em + 0.25vw);}实战案例#
响应式导航#
.navbar { display: flex; justify-content: space-between; align-items: center; padding: 1rem;}
.nav-links { display: none;}
.nav-toggle { display: block;}
@media (min-width: 768px) { .nav-links { display: flex; gap: 1.5rem; }
.nav-toggle { display: none; }}<nav class="navbar"> <a class="logo" href="/">Logo</a> <ul class="nav-links"> <li><a href="/">首页</a></li> <li><a href="/about">关于</a></li> <li><a href="/blog">博客</a></li> </ul> <button class="nav-toggle">☰</button></nav>响应式卡片网格#
.card-grid { display: grid; gap: 1.5rem; padding: 1rem;}
/* 移动端:单列 */.card { padding: 1rem; background: white; border-radius: 8px; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);}
/* 平板:两列 */@media (min-width: 640px) { .card-grid { grid-template-columns: repeat(2, 1fr); }}
/* 桌面:三列 */@media (min-width: 1024px) { .card-grid { grid-template-columns: repeat(3, 1fr); }
.card { padding: 1.5rem; }}
/* 或使用 auto-fit 自动响应 */.card-grid-auto { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 1.5rem;}响应式侧边栏布局#
.layout { display: flex; flex-direction: column; min-height: 100vh;}
.sidebar { padding: 1rem; background: #f9fafb;}
.main-content { flex: 1; padding: 1rem;}
@media (min-width: 768px) { .layout { flex-direction: row; }
.sidebar { width: 250px; flex-shrink: 0; }
.main-content { padding: 2rem; }}响应式表格#
/* 移动端:卡片式 */@media (max-width: 639px) { table, thead, tbody, th, td, tr { display: block; }
thead { display: none; }
tr { margin-bottom: 1rem; border: 1px solid #e5e7eb; border-radius: 8px; }
td { padding: 0.75rem 1rem; border-bottom: 1px solid #e5e7eb; }
td::before { content: attr(data-label); font-weight: 600; display: block; margin-bottom: 0.25rem; color: #6b7280; }}
/* 桌面:传统表格 */@media (min-width: 640px) { table { width: 100%; border-collapse: collapse; }
th, td { padding: 0.75rem 1rem; text-align: left; border-bottom: 1px solid #e5e7eb; }}<table> <thead> <tr> <th>姓名</th> <th>邮箱</th> <th>角色</th> </tr> </thead> <tbody> <tr> <td data-label="姓名">张三</td> <td data-label="邮箱">zhang@example.com</td> <td data-label="角色">管理员</td> </tr> </tbody></table>调试技巧#
浏览器开发者工具#
- Chrome DevTools → 设备工具栏(Ctrl/Cmd + Shift + M)
- 可以模拟各种设备和分辨率
- 查看当前激活的媒体查询
显示当前断点#
body::before { position: fixed; bottom: 0; right: 0; padding: 0.5rem 1rem; background: #1f2937; color: white; font-size: 0.75rem; z-index: 9999; content: 'xs';}
@media (min-width: 640px) { body::before { content: 'sm'; }}@media (min-width: 768px) { body::before { content: 'md'; }}@media (min-width: 1024px) { body::before { content: 'lg'; }}@media (min-width: 1280px) { body::before { content: 'xl'; }}响应式设计是现代 Web 开发的标配。掌握媒体查询、采用移动优先策略、善用响应式单位,你就能让网站在任何设备上都有良好的体验。下一篇我们将学习伪类和伪元素,它们能让 CSS 选择器更加强大。