跳到主要内容

CSS 响应式设计

响应式设计是一种让网页能够自适应不同屏幕尺寸的设计方法。从手机到平板到桌面显示器,用户可能通过各种设备访问你的网站。响应式设计确保网站在任何设备上都能提供良好的用户体验,而不需要为每种设备单独开发版本。

视口设置

响应式设计的第一步是正确设置视口。在 HTML 文档的 <head> 中添加:

<meta name="viewport" content="width=device-width, initial-scale=1.0">

这个元标签告诉移动浏览器:

  • width=device-width:视口宽度等于设备宽度
  • initial-scale=1.0:初始缩放比例为 100%

没有这个设置,移动浏览器可能会以桌面版宽度(如 980px)渲染页面,然后缩放显示,导致文字太小、需要手动放大才能阅读。

禁止用户缩放(不推荐):

<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">

这会阻止用户缩放页面,对视力不好的用户不友好,应该避免使用。

媒体查询

媒体查询是响应式设计的核心技术,它允许根据设备特性(如屏幕宽度)应用不同的 CSS 规则。

基本语法

@media (条件) {
/* 当条件满足时应用的样式 */
}

宽度查询

最常见的媒体查询是基于视口宽度:

/* 视口宽度大于等于 768px */
@media (min-width: 768px) {
.container {
max-width: 750px;
}
}

/* 视口宽度小于等于 576px */
@media (max-width: 576px) {
.container {
padding: 10px;
}
}

/* 宽度范围 */
@media (min-width: 768px) and (max-width: 1024px) {
.container {
max-width: 960px;
}
}

断点选择

断点是媒体查询中的宽度阈值。常用的断点参考:

/* 手机(纵向) */
@media (max-width: 575px) { }

/* 手机(横向)和小平板 */
@media (min-width: 576px) and (max-width: 767px) { }

/* 平板 */
@media (min-width: 768px) and (max-width: 991px) { }

/* 小桌面 */
@media (min-width: 992px) and (max-width: 1199px) { }

/* 大桌面 */
@media (min-width: 1200px) { }

断点应该基于内容需求而非特定设备,因为设备尺寸多种多样。

移动优先 vs 桌面优先

移动优先:先编写移动端样式,再用媒体查询扩展到大屏:

/* 默认样式:移动端 */
.container {
padding: 15px;
}

/* 平板及以上 */
@media (min-width: 768px) {
.container {
padding: 30px;
max-width: 750px;
}
}

/* 桌面 */
@media (min-width: 1024px) {
.container {
max-width: 960px;
}
}

桌面优先:先编写桌面端样式,再用媒体查询适配小屏:

/* 默认样式:桌面 */
.container {
padding: 30px;
max-width: 1200px;
}

/* 平板 */
@media (max-width: 1023px) {
.container {
max-width: 960px;
}
}

/* 手机 */
@media (max-width: 767px) {
.container {
padding: 15px;
max-width: none;
}
}

推荐使用移动优先策略,因为:

  • 代码更简洁,大屏样式覆盖小屏样式
  • 更好地关注核心内容
  • 性能更好,移动设备下载的 CSS 更少

其他媒体特性

/* 屏幕方向 */
@media (orientation: portrait) { } /* 纵向 */
@media (orientation: landscape) { } /* 横向 */

/* 分辨率 */
@media (min-resolution: 2dppx) { } /* 高清屏(Retina) */

/* 屏幕类型 */
@media screen { } /* 屏幕 */
@media print { } /* 打印 */
@media speech { } /* 语音合成 */

/* 悬停能力 */
@media (hover: hover) { } /* 支持悬停(鼠标) */
@media (hover: none) { } /* 不支持悬停(触摸) */

/* 指针精度 */
@media (pointer: fine) { } /* 精确指针(鼠标) */
@media (pointer: coarse) { } /* 粗糙指针(手指) */

/* 组合条件 */
@media screen and (min-width: 768px) and (orientation: landscape) { }
@media (min-width: 768px), (orientation: landscape) { } /* 或 */

在 CSS 文件中引入

/* 方式一:直接写在样式表中 */
.element { /* 默认样式 */ }
@media (min-width: 768px) {
.element { /* 大屏样式 */ }
}

/* 方式二:使用 @import */
@import url('mobile.css') screen and (max-width: 767px);
@import url('desktop.css') screen and (min-width: 768px);

在 HTML 中引入

<link rel="stylesheet" href="mobile.css" media="(max-width: 767px)">
<link rel="stylesheet" href="desktop.css" media="(min-width: 768px)">

响应式布局技术

相对单位

使用相对单位让元素尺寸随视口变化:

/* 相对于根元素字体大小 */
html { font-size: 16px; }
h1 { font-size: 2rem; } /* 32px */

/* 视口单位 */
.hero { height: 100vh; } /* 视口高度 */
.width { width: 80vw; } /* 视口宽度 */
.responsive { font-size: clamp(1rem, 2.5vw, 2rem); }

/* 百分比 */
.container { width: 90%; max-width: 1200px; }
.sidebar { width: 25%; }

clamp() 函数设置值的下限、首选值和上限:

.title {
font-size: clamp(1.5rem, 4vw, 3rem);
/* 最小 1.5rem,首选 4vw,最大 3rem */
}

.width {
width: clamp(300px, 80%, 800px);
}

弹性布局

Flexbox 和 Grid 天然支持响应式:

/* Flexbox 换行 */
.flex-container {
display: flex;
flex-wrap: wrap;
}

.flex-item {
flex: 1 1 300px; /* 最小 300px,自动换行 */
}

/* Grid 自动填充 */
.grid-container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 20px;
}

响应式布局模式

从堆叠到并排

/* 默认:手机堆叠 */
.layout {
display: flex;
flex-direction: column;
}

/* 平板及以上:并排 */
@media (min-width: 768px) {
.layout {
flex-direction: row;
}
}

Grid 响应式

.grid {
display: grid;
gap: 20px;
grid-template-columns: 1fr;
}

@media (min-width: 576px) {
.grid {
grid-template-columns: repeat(2, 1fr);
}
}

@media (min-width: 992px) {
.grid {
grid-template-columns: repeat(4, 1fr);
}
}

隐藏/显示元素

.mobile-only {
display: block;
}
@media (min-width: 768px) {
.mobile-only {
display: none;
}
}

.desktop-only {
display: none;
}
@media (min-width: 768px) {
.desktop-only {
display: block;
}
}

响应式图片

max-width 图片

最简单的响应式图片:

img {
max-width: 100%;
height: auto;
}

图片不会超过容器宽度,高度自动调整保持比例。

srcset 和 sizes

srcset 提供不同分辨率的图片,让浏览器选择最合适的:

<img 
src="small.jpg"
srcset="small.jpg 480w, medium.jpg 800w, large.jpg 1200w"
sizes="(max-width: 600px) 480px, (max-width: 1000px) 800px, 1200px"
alt="响应式图片"
>

sizes 告诉浏览器图片在不同断点下的显示宽度,浏览器根据这些信息和设备像素比选择合适的图片。

picture 元素

<picture> 提供更精细的图片控制:

<picture>
<!-- 根据媒体查询选择 -->
<source media="(min-width: 800px)" srcset="large.webp">
<source media="(min-width: 400px)" srcset="medium.webp">
<source srcset="small.webp">

<!-- 根据格式选择 -->
<source srcset="image.avif" type="image/avif">
<source srcset="image.webp" type="image/webp">

<!-- 默认图片 -->
<img src="fallback.jpg" alt="描述">
</picture>

art direction

在不同屏幕尺寸下使用不同裁剪的图片:

<picture>
<source media="(min-width: 800px)" srcset="wide-crop.jpg">
<source media="(min-width: 400px)" srcset="medium-crop.jpg">
<img src="mobile-crop.jpg" alt="移动端裁剪版本">
</picture>

背景图片响应式

.hero {
background-image: url('small.jpg');
background-size: cover;
background-position: center;
}

@media (min-width: 768px) {
.hero {
background-image: url('medium.jpg');
}
}

@media (min-width: 1200px) {
.hero {
background-image: url('large.jpg');
}
}

使用 image-set() 函数:

.hero {
background-image: image-set(
'small.jpg' 1x,
'medium.jpg' 2x,
'large.jpg' 3x
);
}

响应式排版

相对字体大小

html {
font-size: 100%; /* 浏览器默认,通常 16px */
}

body {
font-size: 1rem;
}

h1 {
font-size: clamp(1.75rem, 4vw, 3rem);
}

行高和间距

body {
line-height: 1.5;
}

@media (min-width: 768px) {
body {
line-height: 1.6;
}
}

.container {
padding: 5%;
}

@media (min-width: 768px) {
.container {
padding: 3rem;
}
}

响应式导航

汉堡菜单模式

<nav class="nav">
<button class="nav-toggle" aria-label="菜单">
<span></span>
</button>

<ul class="nav-menu">
<li><a href="#">首页</a></li>
<li><a href="#">产品</a></li>
<li><a href="#">关于</a></li>
</ul>
</nav>
.nav-menu {
display: none;
}

.nav-menu.active {
display: flex;
flex-direction: column;
}

@media (min-width: 768px) {
.nav-toggle {
display: none;
}

.nav-menu {
display: flex;
flex-direction: row;
}
}

测试响应式设计

浏览器开发者工具

Chrome、Firefox 等浏览器都提供设备模拟功能:

  1. 打开开发者工具(F12)
  2. 点击设备工具栏图标
  3. 选择预设设备或自定义尺寸

测试要点

  • 在各种尺寸下检查布局是否正常
  • 文字是否清晰可读
  • 触摸目标是否足够大(至少 44x44 像素)
  • 图片是否正确加载和显示
  • 导航是否可用

小结

这一章我们学习了:

  • 视口设置的重要性
  • 媒体查询的语法和使用
  • 移动优先的设计策略
  • 响应式布局技术
  • 响应式图片的处理方法
  • 响应式排版

响应式设计是现代 Web 开发的必备技能。记住几个关键点:

  • 始终设置 viewport 元标签
  • 使用移动优先策略
  • 使用相对单位和弹性布局
  • 选择合适的断点
  • 测试各种设备和尺寸

下一章我们将学习 CSS 动画与过渡,为网页添加动态效果。