跳到主要内容

CSS 响应式设计

响应式设计使网页能够适配不同尺寸的设备,从手机到桌面显示器。

响应式设计基础

什么是响应式设计?

响应式设计是一种让网页布局根据设备屏幕尺寸自动调整的方法:

  • 移动优先:从小屏幕开始设计
  • 流式布局:使用相对单位而非固定像素
  • 媒体查询:根据屏幕条件应用不同样式

viewport 视口

<!-- 必须设置! -->
<meta name="viewport" content="width=device-width, initial-scale=1.0">

视口属性说明:

属性说明
width视口宽度,device-width 表示设备宽度
initial-scale初始缩放比例
minimum-scale最小缩放比例
maximum-scale最大缩放比例
user-scalable是否允许用户缩放

媒体查询 @media

基本语法

/* 屏幕宽度小于768px时生效 */
@media (max-width: 768px) {
body {
font-size: 14px;
}
}

媒体类型

/* screen: 屏幕设备 */
@media screen { }

/* print: 打印机 */
@media print {
.navbar, .sidebar { display: none; }
}

/* all: 所有设备(默认) */
@media all { }

媒体条件

/* 最小宽度 */
@media (min-width: 768px) { }

/* 最大宽度 */
@media (max-width: 768px) { }

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

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

/* 设备像素比 */
@media (-webkit-min-device-pixel-ratio: 2) { }

常用断点

/* 移动端 */
@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) { }

响应式布局策略

1. 移动优先 vs 桌面优先

移动优先(推荐)

/* 默认:移动端样式 */
.container { width: 100%; }

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

/* 桌面及以上 */
@media (min-width: 992px) {
.container { width: 970px; }
}

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

桌面优先

/* 默认:桌面样式 */
.container { width: 1170px; }

/* 平板及以下 */
@media (max-width: 991px) {
.container { width: 750px; }
}

/* 手机及以下 */
@media (max-width: 767px) {
.container { width: 100%; }
}

2. 流式网格

.container {
width: 100%;
max-width: 1200px;
margin: 0 auto;
padding: 0 15px;
}

.grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 20px;
}

/* 响应式:减少列数 */
@media (max-width: 991px) {
.grid { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 575px) {
.grid { grid-template-columns: 1fr; }
}

3. Flexbox 响应式

.nav {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}

.nav-links {
display: flex;
gap: 20px;
}

/* 移动端:垂直排列 */
@media (max-width: 767px) {
.nav {
flex-direction: column;
}
.nav-links {
flex-direction: column;
gap: 10px;
}
}

4. 图片响应式

/* 基础 */
img {
max-width: 100%;
height: auto;
}

/* 响应式图片 */
<img src="small.jpg"
srcset="small.jpg 500w, medium.jpg 1000w, large.jpg 1500w"
sizes="(max-width: 600px) 100vw, 50vw"
alt="描述">

/* picture 元素 */
<picture>
<source media="(max-width: 600px)" srcset="mobile.jpg">
<source media="(min-width: 601px)" srcset="desktop.jpg">
<img src="default.jpg" alt="描述">
</picture>

5. 隐藏元素

.desktop-only {
display: none;
}

.mobile-only {
display: block;
}

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

响应式组件

1. 响应式导航栏

/* 默认:移动端(汉堡菜单) */
.navbar {
display: flex;
flex-direction: column;
padding: 10px;
}

.menu-toggle {
display: block;
align-self: flex-end;
}

.nav-links {
display: none;
flex-direction: column;
}

/* 激活菜单 */
.nav-links.active {
display: flex;
}

/* 平板及以上 */
@media (min-width: 768px) {
.navbar {
flex-direction: row;
justify-content: space-between;
align-items: center;
}

.menu-toggle {
display: none;
}

.nav-links {
display: flex;
flex-direction: row;
gap: 20px;
}
}

2. 响应式卡片

.card-container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 20px;
}

.card {
display: flex;
flex-direction: column;
padding: 20px;
}

.card img {
width: 100%;
height: 200px;
object-fit: cover;
}

@media (max-width: 575px) {
.card {
padding: 15px;
}
.card img {
height: 150px;
}
}

3. 响应式表单

.form-row {
display: flex;
gap: 20px;
margin-bottom: 15px;
}

.form-group {
flex: 1;
}

@media (max-width: 575px) {
.form-row {
flex-direction: column;
gap: 0;
}
}

4. 响应式表格

/* 横向滚动 */
.table-container {
overflow-x: auto;
}

/* 卡片式转换 */
@media (max-width: 767px) {
table, thead, tbody, th, td, tr {
display: block;
}

thead { display: none; }

tr {
margin-bottom: 15px;
border: 1px solid #ddd;
}

td {
padding: 10px 10px 10px 40%;
position: relative;
}

td::before {
content: attr(data-label);
position: absolute;
left: 10px;
font-weight: bold;
}
}
<table>
<thead>
<tr>
<th>姓名</th>
<th>年龄</th>
<th>城市</th>
</tr>
</thead>
<tbody>
<tr>
<td data-label="姓名">张三</td>
<td data-label="年龄">25</td>
<td data-label="城市">北京</td>
</tr>
</tbody>
</table>

响应式字体

1. 使用相对单位

html { font-size: 16px; }

body { font-size: 1rem; } /* 16px */
h1 { font-size: 2rem; } /* 32px */
p { font-size: 1rem; } /* 16px */

2. CSS clamp()

/* 响应式字体大小:最小14px,最大24px,优先18px */
h1 {
font-size: clamp(1.75rem, 2.5vw, 3rem);
}

p {
font-size: clamp(0.875rem, 1.5vw, 1.125rem);
}

3. 媒体查询调整

html { font-size: 14px; }

@media (min-width: 768px) {
html { font-size: 16px; }
}

@media (min-width: 1200px) {
html { font-size: 18px; }
}

响应式间距

/* 基础间距 */
.section {
padding: 20px;
}

/* 响应式间距 */
@media (min-width: 768px) {
.section { padding: 40px; }
}

@media (min-width: 1200px) {
.section { padding: 60px 0; }
}

/* 使用 CSS 变量 */
:root {
--spacing-sm: 10px;
--spacing-md: 20px;
--spacing-lg: 40px;
}

@media (min-width: 768px) {
:root {
--spacing-sm: 15px;
--spacing-md: 30px;
--spacing-lg: 60px;
}
}

常用响应式模式

1. 侧边栏布局

.layout {
display: grid;
grid-template-columns: 250px 1fr;
}

@media (max-width: 767px) {
.layout {
grid-template-columns: 1fr;
}
.sidebar { display: none; }
}

2. 卡片网格

.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
}

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

@media (max-width: 575px) {
.grid { grid-template-columns: 1fr; }
}

3. 堆叠到并排

.content {
display: flex;
flex-direction: column;
}

@media (min-width: 768px) {
.content {
flex-direction: row;
}
.main { flex: 2; }
.sidebar { flex: 1; }
}

测试工具

浏览器开发者工具

  1. 按 F12 打开开发者工具
  2. 点击设备模拟图标(手机图标)
  3. 选择不同设备或自定义尺寸

在线工具

小结

本章学习了:

  1. 响应式基础:viewport 设置、移动优先理念
  2. 媒体查询:条件语法、常用断点
  3. 布局策略:流式网格、Flexbox 响应式、隐藏元素
  4. 响应式组件:导航、卡片、表单、表格
  5. 响应式内容:图片、字体、间距

练习

  1. 为现有页面添加响应式设计
  2. 创建一套响应式网格系统
  3. 实现一个响应式导航栏
  4. 将表格转换为移动端卡片布局
  5. 使用 clamp() 实现响应式字体