meta 视口设置
<meta name="viewport"> 标签是移动端 Web 开发的基础,它控制着浏览器在移动设备上如何渲染和缩放页面。没有正确的 viewport 设置,页面在手机上会以桌面版宽度显示,导致内容过小、需要手动缩放。
前置知识
阅读本节前,建议先了解:meta 字符编码
基础概念
什么是视口(Viewport)
视口是浏览器窗口中用于显示网页内容的区域。在桌面端,视口宽度通常等于浏览器窗口宽度。但在移动设备上,情况有所不同:
桌面端视口:
- 视口宽度 = 浏览器窗口宽度
- 1 个 CSS 像素 = 1 个设备像素(不考虑缩放)
移动端视口:
- 有两个视口概念:布局视口(Layout Viewport)和视觉视口(Visual Viewport)
- 布局视口:浏览器用于计算 CSS 布局的虚拟宽度,通常为 980px(默认值)
- 视觉视口:用户在屏幕上实际看到的区域
没有 viewport 设置时的默认行为
当移动端浏览器打开一个没有 viewport 声明的页面时:
- 浏览器会将布局视口设为较大的固定宽度(通常 980px 或 1024px)
- 页面按照这个宽度进行布局
- 然后将整个页面缩小到适应屏幕宽度
- 用户看到的是缩小版的桌面页面,文字很小
<!-- 没有 viewport 设置 -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>没有 viewport</title>
</head>
<body>
<p>这个页面在手机上会显示得很小,需要手动放大。</p>
</body>
</html>有 viewport 设置后的行为
<!-- 有 viewport 设置 -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>有 viewport</title>
</head>
<body>
<p>这个页面在手机上会以合适的宽度显示,文字清晰可读。</p>
</body>
</html>语法
基本语法
<meta name="viewport" content="width=device-width, initial-scale=1.0">viewport 属性详解
content 属性可以包含多个设置项,用逗号分隔:
| 属性 | 值 | 说明 |
|---|---|---|
width | 正整数 或 device-width | 设置布局视口宽度 |
initial-scale | 0.1 ~ 10 | 初始缩放比例 |
minimum-scale | 0.1 ~ 10 | 最小缩放比例 |
maximum-scale | 0.1 ~ 10 | 最大缩放比例 |
user-scalable | yes 或 no | 是否允许用户缩放 |
height | 正整数 或 device-height | 设置布局视口高度(很少使用) |
viewport-fit | auto / contain / cover | 适配安全区域(如刘海屏) |
属性详细说明
width
<!-- 布局视口宽度等于设备宽度 -->
<meta name="viewport" content="width=device-width">
<!-- 布局视口宽度固定为 320px(不推荐) -->
<!-- <meta name="viewport" content="width=320"> -->device-width表示将布局视口宽度设为设备屏幕宽度- 也可以设置固定像素值,但不推荐,这违背了响应式设计的初衷
- 这是响应式设计的最关键设置
initial-scale
<!-- 初始缩放比例为 1.0(不缩放) -->
<meta name="viewport" content="initial-scale=1.0">
<!-- 初始缩放比例为 0.5(缩小到 50%) -->
<!-- <meta name="viewport" content="initial-scale=0.5"> -->1.0表示 100%,即不缩放0.5表示 50%,页面会缩小到一半2.0表示 200%,页面会放大到两倍- 推荐使用
1.0
minimum-scale 和 maximum-scale
<!-- 限制缩放范围在 0.5 ~ 2.0 之间 -->
<meta name="viewport" content="minimum-scale=0.5, maximum-scale=2.0">
<!-- 不推荐:禁止缩放 -->
<!-- <meta name="viewport" content="maximum-scale=1.0, user-scalable=no"> -->无障碍警告
设置 user-scalable=no 或 maximum-scale=1.0 会禁止用户缩放页面,这违反了 WCAG 无障碍标准。对于视力不佳的用户,缩放是必要的辅助功能。除非有特殊需求(如类原生应用的 Web 页面),否则不应禁止缩放。
viewport-fit(安全区域适配)
<!-- 适配刘海屏等异形屏 -->
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">viewport-fit 属性用于适配 iPhone X 等带有刘海屏或圆角的设备:
| 值 | 说明 |
|---|---|
auto(默认) | 不扩展到安全区域外 |
contain | 视口缩放以适应屏幕 |
cover | 视口扩展到整个屏幕,可能被刘海遮挡 |
配合 CSS 的 env() 函数使用:
/* 适配安全区域 */
body {
padding-top: env(safe-area-inset-top);
padding-bottom: env(safe-area-inset-bottom);
padding-left: env(safe-area-inset-left);
padding-right: env(safe-area-inset-right);
}详细说明
三种视口类型
| 视口类型 | 英文 | 说明 |
|---|---|---|
| 布局视口 | Layout Viewport | 浏览器用于 CSS 布局计算的宽度 |
| 视觉视口 | Visual Viewport | 用户在屏幕上实际看到的区域 |
| 理想视口 | Ideal Viewport | 布局视口 = 设备宽度,不需要缩放就能正常显示 |
常见设备宽度
| 设备 | 设备宽度(CSS 像素) | 设备像素比(DPR) |
|---|---|---|
| iPhone SE | 375px | 2 |
| iPhone 14 | 390px | 3 |
| iPhone 14 Pro Max | 430px | 3 |
| iPad Mini | 768px | 2 |
| iPad Pro 12.9" | 1024px | 2 |
| Samsung Galaxy S23 | 360px | 3 |
| 大多数 Android 手机 | 360px ~ 412px | 2~3 |
完整的 viewport 推荐配置
<!-- 标准配置(适用于大多数网站) -->
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- 完整配置(包含所有参数) -->
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=5.0, user-scalable=yes">
<!-- 适配刘海屏的配置 -->
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">viewport 与响应式设计的关系
viewport 设置是响应式设计的前提条件。没有正确的 viewport,媒体查询将无法正常工作:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>响应式设计示例</title>
<style>
.container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
/* 桌面端:两列布局 */
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
}
/* 平板端:两列 */
@media (max-width: 768px) {
.grid {
grid-template-columns: repeat(2, 1fr);
}
}
/* 手机端:单列 */
@media (max-width: 480px) {
.grid {
grid-template-columns: 1fr;
}
}
.card {
background: #f0f0f0;
padding: 20px;
border-radius: 8px;
text-align: center;
}
</style>
</head>
<body>
<div class="container">
<h1>响应式网格布局</h1>
<div class="grid">
<div class="card">卡片 1</div>
<div class="card">卡片 2</div>
<div class="card">卡片 3</div>
<div class="card">卡片 4</div>
<div class="card">卡片 5</div>
<div class="card">卡片 6</div>
</div>
</div>
</body>
</html>viewport 设置的常见错误
1. 缺少 viewport 声明
<!-- 错误!移动端页面没有 viewport 设置 -->
<head>
<meta charset="UTF-8">
<title>我的网站</title>
</head>2. 使用固定宽度
<!-- 不推荐!固定宽度无法适应不同设备 -->
<meta name="viewport" content="width=320">
<!-- 推荐 -->
<meta name="viewport" content="width=device-width">3. 禁止用户缩放
<!-- 不推荐!影响无障碍性 -->
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<!-- 推荐 -->
<meta name="viewport" content="width=device-width, initial-scale=1.0">4. 设置多个 viewport 标签
<!-- 错误!只能有一个 viewport 标签 -->
<meta name="viewport" content="width=device-width">
<meta name="viewport" content="initial-scale=1.0">
<!-- 正确:合并为一个 -->
<meta name="viewport" content="width=device-width, initial-scale=1.0">实战示例
viewport 信息查看器
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Viewport 信息查看器</title>
<style>
body {
font-family: system-ui, sans-serif;
margin: 0;
padding: 20px;
background: #f5f5f5;
line-height: 1.6;
}
.info-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 15px;
max-width: 600px;
margin: 20px auto;
}
.info-card {
background: white;
border-radius: 8px;
padding: 15px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.info-card h3 {
margin: 0 0 8px;
color: #666;
font-size: 14px;
}
.info-card .value {
font-size: 24px;
font-weight: bold;
color: #0066cc;
}
.info-card .unit {
font-size: 14px;
color: #999;
}
@media (max-width: 480px) {
.info-grid {
grid-template-columns: 1fr;
}
}
</style>
</head>
<body>
<h1 style="text-align:center;">Viewport 信息查看器</h1>
<p style="text-align:center; color:#666;">
缩放浏览器窗口或在不同设备上查看此页面
</p>
<div class="info-grid">
<div class="info-card">
<h3>窗口宽度 (window.innerWidth)</h3>
<div class="value" id="win-width">-</div>
<div class="unit">CSS 像素</div>
</div>
<div class="info-card">
<h3>窗口高度 (window.innerHeight)</h3>
<div class="value" id="win-height">-</div>
<div class="unit">CSS 像素</div>
</div>
<div class="info-card">
<h3>设备宽度 (screen.width)</h3>
<div class="value" id="screen-width">-</div>
<div class="unit">设备像素</div>
</div>
<div class="info-card">
<h3>设备像素比 (devicePixelRatio)</h3>
<div class="value" id="dpr">-</div>
<div class="unit">倍</div>
</div>
<div class="info-card">
<h3>物理宽度 (screen.width * DPR)</h3>
<div class="value" id="physical-width">-</div>
<div class="unit">物理像素</div>
</div>
<div class="info-card">
<h3>布局视口宽度</h3>
<div class="value" id="layout-width">-</div>
<div class="unit">CSS 像素</div>
</div>
</div>
<script>
function updateInfo() {
document.getElementById('win-width').textContent = window.innerWidth;
document.getElementById('win-height').textContent = window.innerHeight;
document.getElementById('screen-width').textContent = screen.width;
document.getElementById('dpr').textContent = window.devicePixelRatio;
document.getElementById('physical-width').textContent =
screen.width * window.devicePixelRatio;
document.getElementById('layout-width').textContent =
document.documentElement.clientWidth;
}
updateInfo();
window.addEventListener('resize', updateInfo);
</script>
</body>
</html>响应式图片与 viewport
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>响应式图片</title>
<style>
img {
max-width: 100%;
height: auto;
display: block;
margin: 20px auto;
}
.info {
text-align: center;
color: #666;
font-family: system-ui, sans-serif;
padding: 20px;
}
</style>
</head>
<body>
<p class="info">
当前视口宽度: <b id="viewport-width">-</b>px
</p>
<!-- 使用 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, 800px"
alt="响应式图片示例"
>
<script>
function updateWidth() {
document.getElementById('viewport-width').textContent =
window.innerWidth;
}
updateWidth();
window.addEventListener('resize', updateWidth);
</script>
</body>
</html>注意事项
1. viewport 只影响移动端行为
在桌面浏览器中,<meta name="viewport"> 通常不会产生明显效果。桌面浏览器的布局视口始终等于窗口宽度。
2. 不要为桌面页面添加 viewport
如果你的网站只有桌面版本,不需要添加 viewport 标签。但现代 Web 开发中,响应式设计已经成为标准,几乎所有网站都应该添加。
3. 双击缩放与 300ms 延迟
在移动端,user-scalable=yes 时,浏览器会检测双击缩放手势,这可能导致点击事件有约 300ms 的延迟。现代浏览器已通过 <meta name="viewport" content="width=device-width"> 消除了这个问题。
4. 横屏与竖屏
viewport 设置在横屏和竖屏切换时会自动更新。device-width 的值会随屏幕方向变化。
最佳实践
1. 每个页面都添加标准 viewport 声明
<meta name="viewport" content="width=device-width, initial-scale=1.0">2. 不要禁止用户缩放
<!-- 不推荐 -->
<!-- <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"> -->3. 如果需要适配刘海屏
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">配合 CSS env() 函数处理安全区域。
4. 使用 CSS 媒体查询做响应式适配
viewport 只是设置了正确的视口宽度,实际的响应式布局需要配合 CSS 媒体查询。
5. 测试多种设备宽度
使用浏览器的开发者工具模拟不同设备宽度,确保页面在各种尺寸下都能正常显示。
viewport 速查表
| 配置 | 代码 |
|---|---|
| 标准配置 | <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| 禁止缩放 | ..., maximum-scale=1.0, user-scalable=no(不推荐) |
| 刘海屏适配 | ..., viewport-fit=cover |
| 限制缩放范围 | ..., minimum-scale=0.5, maximum-scale=3.0 |
下一节
继续学习:meta 描述与关键词