Skip to content

响应式设计

现代网站需要在手机、平板、笔记本、大屏显示器等各种设备上良好呈现。响应式设计让同一份 HTML 和 CSS 能够自动适配不同屏幕尺寸,提供一致的用户体验。

视口设置#

响应式设计的第一步是正确设置视口:

<meta name="viewport" content="width=device-width, initial-scale=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) {
}

常见框架的断点值:

断点TailwindCSSBootstrap
sm640px576px
md768px768px
lg1024px992px
xl1280px1200px
2xl1536px1400px

移动优先 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;
}
}

🎯 为什么推荐移动优先?

  1. 移动端样式通常更简单,便于扩展
  2. 符合渐进增强原则
  3. 移动设备性能有限,先加载基础样式更高效

响应式单位#

相对单位#

/* 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; /* 动态视口高度,考虑地址栏 */
}

新的视口单位:

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>

调试技巧#

浏览器开发者工具#

  1. Chrome DevTools → 设备工具栏(Ctrl/Cmd + Shift + M)
  2. 可以模拟各种设备和分辨率
  3. 查看当前激活的媒体查询

显示当前断点#

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 选择器更加强大。