在多设备时代,响应式设计已成为标配。一个优秀的响应式网站能够在手机、平板、桌面等各种设备上提供最佳体验。
响应式设计基础#
视口设置#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
| <!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<!-- 关键视口设置 -->
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- 可选的扩展设置 -->
<!-- 禁止用户缩放(谨慎使用) -->
<!-- <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> -->
<!-- iOS Safari特定设置 -->
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<!-- Android Chrome特定设置 -->
<meta name="theme-color" content="#3b82f6">
<!-- PWA相关 -->
<link rel="manifest" href="/manifest.json">
</head>
<body>
<!-- 内容 -->
</body>
</html>
|
媒体查询#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
| /**
* 媒体查询断点设置
* 推荐的移动优先方法
*/
/* ===== 移动优先:默认样式(最小屏幕) ===== */
.container {
width: 100%;
padding: 0 16px;
max-width: 100%;
}
/* ===== 小型手机(< 576px)===== */
/* 默认样式覆盖此范围 */
/* ===== 手机(≥ 576px)===== */
@media (min-width: 576px) {
.container {
max-width: 540px;
margin: 0 auto;
}
}
/* ===== 平板竖屏(≥ 768px)===== */
@media (min-width: 768px) {
.container {
max-width: 720px;
}
.grid {
grid-template-columns: repeat(2, 1fr);
}
}
/* ===== 平板横屏(≥ 992px)===== */
@media (min-width: 992px) {
.container {
max-width: 960px;
}
.grid {
grid-template-columns: repeat(3, 1fr);
}
}
/* ===== 桌面(≥ 1200px)===== */
@media (min-width: 1200px) {
.container {
max-width: 1140px;
}
.grid {
grid-template-columns: repeat(4, 1fr);
}
}
/* ===== 大屏(≥ 1400px)===== */
@media (min-width: 1400px) {
.container {
max-width: 1320px;
}
}
/**
* 高分辨率屏幕优化
*/
@media (-webkit-min-device-pixel-ratio: 2),
(min-resolution: 192dpi) {
/* Retina屏幕样式 */
.logo {
background-image: url('logo@2x.png');
background-size: 100px 50px;
}
}
/**
* 打印样式
*/
@media print {
/* 隐藏不需要打印的元素 */
.no-print,
nav,
footer,
.sidebar {
display: none !important;
}
/* 优化打印布局 */
body {
font-size: 12pt;
line-height: 1.5;
color: #000;
}
a {
color: #000;
text-decoration: underline;
}
/* 显示链接URL */
a[href^="http"]::after {
content: " (" attr(href) ")";
}
/* 避免分页时断开内容 */
h1, h2, h3 {
page-break-after: avoid;
}
img {
max-width: 100%;
page-break-inside: avoid;
}
}
/**
* 深色模式支持
*/
@media (prefers-color-scheme: dark) {
:root {
--bg-primary: #111827;
--text-primary: #f9fafb;
--bg-secondary: #1f2937;
--text-secondary: #d1d5db;
}
body {
background-color: var(--bg-primary);
color: var(--text-primary);
}
}
/**
* 减少动画偏好
*/
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
|
流式布局#
弹性盒布局#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
| /**
* Flexbox响应式布局
*/
/* 1. 自适应卡片布局 */
.card-container {
display: flex;
flex-wrap: wrap;
gap: 16px;
}
.card {
/* 自动计算宽度,每行显示的卡片数随容器宽度变化 */
flex: 1 1 300px;
min-width: 0; /* 防止内容溢出 */
}
/* 2. 响应式导航栏 */
.navbar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 16px;
}
.navbar-brand {
flex-shrink: 0; /* 品牌标志不缩放 */
}
.navbar-menu {
display: flex;
gap: 24px;
}
/* 移动端隐藏菜单 */
@media (max-width: 768px) {
.navbar-menu {
display: none;
position: absolute;
top: 100%;
left: 0;
right: 0;
flex-direction: column;
background: white;
padding: 16px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
.navbar-menu.active {
display: flex;
}
.navbar-toggle {
display: block;
}
}
@media (min-width: 769px) {
.navbar-toggle {
display: none;
}
}
/* 3. 等高列 */
.equal-height-container {
display: flex;
flex-wrap: wrap;
}
.equal-height-item {
flex: 1 1 300px;
/* 所有列自动等高 */
}
/* 4. 垂直居中 */
.centered {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
|
网格布局#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
| /**
* CSS Grid响应式布局
*/
/* 1. 自适应网格 */
.grid-auto {
display: grid;
/* 自动填充,最小200px,最大1fr */
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 16px;
}
/* 2. 自适应网格(紧凑) */
.grid-fit {
display: grid;
/* 自动填充至填满空间,最小200px,最大1fr */
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 16px;
}
/* 3. 响应式网格布局 */
.responsive-grid {
display: grid;
gap: 16px;
/* 移动端:1列 */
grid-template-columns: 1fr;
}
@media (min-width: 576px) {
.responsive-grid {
/* 小屏:2列 */
grid-template-columns: repeat(2, 1fr);
}
}
@media (min-width: 768px) {
.responsive-grid {
/* 平板:3列 */
grid-template-columns: repeat(3, 1fr);
}
}
@media (min-width: 1024px) {
.responsive-grid {
/* 桌面:4列 */
grid-template-columns: repeat(4, 1fr);
}
}
/* 4. 复杂网格布局 */
.complex-layout {
display: grid;
gap: 24px;
/* 定义12列网格 */
grid-template-columns: repeat(12, 1fr);
}
.complex-layout header {
/* 跨越所有列 */
grid-column: 1 / -1;
}
.complex-layout aside {
/* 侧边栏占3列 */
grid-column: 1 / 4;
}
.complex-layout main {
/* 主内容占9列 */
grid-column: 4 / -1;
}
@media (max-width: 768px) {
.complex-layout aside,
.complex-layout main {
/* 移动端都占满宽度 */
grid-column: 1 / -1;
}
}
/* 5. 图片网格 */
.gallery {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 16px;
}
.gallery-item {
position: relative;
aspect-ratio: 16 / 9; /* 保持宽高比 */
overflow: hidden;
}
.gallery-item img {
width: 100%;
height: 100%;
object-fit: cover;
}
|
响应式组件#
响应式导航#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
| <!-- 移动优先的响应式导航 -->
<nav class="navbar">
<div class="navbar-container">
<!-- Logo -->
<a href="/" class="navbar-brand">
<img src="logo.svg" alt="Logo">
</a>
<!-- 移动端菜单按钮 -->
<button class="navbar-toggle" aria-label="Toggle navigation">
<span class="hamburger"></span>
</button>
<!-- 导航菜单 -->
<div class="navbar-menu">
<a href="/" class="navbar-link">首页</a>
<a href="/about" class="navbar-link">关于</a>
<a href="/services" class="navbar-link">服务</a>
<a href="/blog" class="navbar-link">博客</a>
<a href="/contact" class="navbar-link">联系</a>
</div>
</div>
</nav>
<style>
.navbar {
background: white;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
position: sticky;
top: 0;
z-index: 1000;
}
.navbar-container {
max-width: 1200px;
margin: 0 auto;
padding: 0 16px;
display: flex;
justify-content: space-between;
align-items: center;
height: 64px;
}
.navbar-brand img {
height: 40px;
width: auto;
}
.navbar-toggle {
display: none;
flex-direction: column;
gap: 4px;
background: none;
border: none;
cursor: pointer;
padding: 8px;
}
.hamburger {
display: block;
width: 24px;
height: 2px;
background: #333;
position: relative;
transition: background 0.3s;
}
.hamburger::before,
.hamburger::after {
content: '';
position: absolute;
width: 24px;
height: 2px;
background: #333;
transition: transform 0.3s;
}
.hamburger::before {
top: -8px;
}
.hamburger::after {
bottom: -8px;
}
/* 激活状态 */
.navbar-toggle.active .hamburger {
background: transparent;
}
.navbar-toggle.active .hamburger::before {
transform: rotate(45deg);
top: 0;
}
.navbar-toggle.active .hamburger::after {
transform: rotate(-45deg);
bottom: 0;
}
.navbar-menu {
display: flex;
gap: 32px;
}
.navbar-link {
color: #333;
text-decoration: none;
font-weight: 500;
padding: 8px 0;
position: relative;
}
.navbar-link::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
width: 0;
height: 2px;
background: #3b82f6;
transition: width 0.3s;
}
.navbar-link:hover::after {
width: 100%;
}
/* 移动端样式 */
@media (max-width: 768px) {
.navbar-toggle {
display: flex;
}
.navbar-menu {
display: none;
position: absolute;
top: 100%;
left: 0;
right: 0;
flex-direction: column;
background: white;
padding: 16px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
gap: 0;
}
.navbar-menu.active {
display: flex;
}
.navbar-link {
padding: 16px 0;
border-bottom: 1px solid #f0f0f0;
}
.navbar-link:last-child {
border-bottom: none;
}
}
</style>
<script>
const navbarToggle = document.querySelector('.navbar-toggle');
const navbarMenu = document.querySelector('.navbar-menu');
navbarToggle.addEventListener('click', () => {
navbarToggle.classList.toggle('active');
navbarMenu.classList.toggle('active');
});
// 点击菜单项后关闭移动端菜单
document.querySelectorAll('.navbar-link').forEach(link => {
link.addEventListener('click', () => {
if (window.innerWidth <= 768) {
navbarToggle.classList.remove('active');
navbarMenu.classList.remove('active');
}
});
});
</script>
|
响应式图片#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
| <!-- 1. Picture元素 - 艺术指导 -->
<picture>
<!-- 移动端:垂直构图 -->
<source
media="(max-width: 767px)"
srcset="hero-mobile.jpg 1x,
hero-mobile@2x.jpg 2x">
<!-- 平板:中等构图 -->
<source
media="(max-width: 1023px)"
srcset="hero-tablet.jpg 1x,
hero-tablet@2x.jpg 2x">
<!-- 桌面:水平构图 -->
<img
src="hero-desktop.jpg"
srcset="hero-desktop.jpg 1x,
hero-desktop@2x.jpg 2x"
alt="Hero image"
loading="lazy">
</picture>
<!-- 2. srcset - 响应式尺寸 -->
<img
src="image-800.jpg"
srcset="image-400.jpg 400w,
image-800.jpg 800w,
image-1200.jpg 1200w,
image-1600.jpg 1600w"
sizes="(max-width: 600px) 100vw,
(max-width: 1200px) 50vw,
33vw"
alt="Responsive image"
loading="lazy">
<!-- 3. CSS背景图 -->
<style>
.hero {
/* 默认背景图 */
background-image: url('hero-small.jpg');
background-size: cover;
background-position: center;
min-height: 400px;
}
/* 高分辨率屏幕 */
@media (-webkit-min-device-pixel-ratio: 2),
(min-resolution: 192dpi) {
.hero {
background-image: url('hero-small@2x.jpg');
}
}
/* 平板 */
@media (min-width: 768px) {
.hero {
background-image: url('hero-medium.jpg');
min-height: 500px;
}
}
@media (min-width: 768px) and (-webkit-min-device-pixel-ratio: 2),
(min-width: 768px) and (min-resolution: 192dpi) {
.hero {
background-image: url('hero-medium@2x.jpg');
}
}
/* 桌面 */
@media (min-width: 1024px) {
.hero {
background-image: url('hero-large.jpg');
min-height: 600px;
}
}
</style>
|
响应式表格#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
| <!-- 1. 卡片式转换(移动端) -->
<div class="table-responsive">
<table class="data-table">
<thead>
<tr>
<th>姓名</th>
<th>邮箱</th>
<th>电话</th>
<th>状态</th>
</tr>
</thead>
<tbody>
<tr>
<td data-label="姓名">张三</td>
<td data-label="邮箱">zhang@example.com</td>
<td data-label="电话">138-0000-0000</td>
<td data-label="状态">活跃</td>
</tr>
<!-- 更多行 -->
</tbody>
</table>
</div>
<style>
.table-responsive {
overflow-x: auto;
-webkit-overflow-scrolling: touch;
}
/* 移动端转换为卡片 */
@media (max-width: 768px) {
.data-table,
.data-table tbody,
.data-table tr,
.data-table td {
display: block;
width: 100%;
}
.data-table thead {
display: none;
}
.data-table tr {
margin-bottom: 16px;
border: 1px solid #ddd;
border-radius: 8px;
padding: 12px;
}
.data-table td {
text-align: left;
padding: 8px 0;
display: flex;
justify-content: space-between;
border-bottom: 1px solid #eee;
}
.data-table td:last-child {
border-bottom: none;
}
.data-table td::before {
content: attr(data-label);
font-weight: 600;
margin-right: 16px;
}
}
</style>
<!-- 2. 水平滚动(移动端) -->
<style>
@media (max-width: 768px) {
.table-wrapper {
overflow-x: auto;
-webkit-overflow-scrolling: touch;
}
.data-table {
min-width: 600px;
}
}
</style>
|
移动端优化#
触摸优化#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
| /**
* 触摸目标尺寸优化
* iOS最小44x44pt,Android最小48x48dp
*/
/* 按钮触摸区域 */
.touch-button {
/* 视觉尺寸 */
padding: 12px 24px;
font-size: 16px;
/* 确保触摸区域足够大 */
min-height: 44px;
min-width: 44px;
}
/* 小图标的触摸区域 */
.icon-button {
position: relative;
width: 44px;
height: 44px;
display: inline-flex;
align-items: center;
justify-content: center;
}
.icon-button svg {
width: 24px;
height: 24px;
}
/* 表单控件触摸优化 */
input[type="text"],
input[type="email"],
input[type="tel"],
select,
textarea {
font-size: 16px; /* 防止iOS自动缩放 */
padding: 12px 16px;
min-height: 44px;
}
/* 移除点击高亮 */
* {
-webkit-tap-highlight-color: transparent;
}
/* 触摸反馈 */
.touch-feedback {
transition: background-color 0.2s, opacity 0.2s;
}
.touch-feedback:active {
background-color: rgba(0, 0, 0, 0.1);
opacity: 0.8;
}
/* 防止长按选中文本 */
.no-select {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
|
移动端特定样式#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
| /**
* iOS Safari特定优化
*/
/* 安全区域适配(iPhone X及以上) */
.page-header {
padding-top: max(16px, env(safe-area-inset-top));
}
.page-footer {
padding-bottom: max(16px, env(safe-area-inset-bottom));
}
.fixed-bottom-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
padding: 16px;
padding-bottom: calc(16px + env(safe-area-inset-bottom));
background: white;
}
/* 修复iOS滚动回弹效果 */
.smooth-scroll {
-webkit-overflow-scrolling: touch;
}
/**
* Android Chrome特定优化
*/
/* 修复Android字体渲染 */
body {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
/* 状态栏颜色(Android Chrome) */
<meta name="theme-color" content="#3b82f6">
<meta name="theme-color" content="#3b82f6" media="(prefers-color-scheme: light)">
<meta name="theme-color" content="#111827" media="(prefers-color-scheme: dark)">
|
响应式设计的核心要点:
- 移动优先:从最小屏幕开始设计,逐步增强
- 弹性布局:使用Flexbox和Grid创建自适应布局
- 媒体查询:根据设备特性应用不同样式
- 响应式资源:使用适当的图片和字体尺寸
- 触摸优化:确保触摸目标足够大,反馈明确
- 测试验证:在各种设备和浏览器上测试
响应式设计不仅是技术实现,更是以用户为中心的设计理念。