移动端适配与 PWA
2025 年全球移动端流量占比超过 60%,但很多 Web 应用仍然是"桌面优先、移动凑合"。移动端适配不仅仅是"屏幕变小"——触摸交互、网络环境、性能预算、离线能力都与桌面端截然不同。PWA(Progressive Web App)更进一步,让 Web 应用具备原生 App 的体验——安装到主屏幕、离线访问、推送通知。本章系统讲解 Next.js 的移动端适配策略和 PWA 实现。
1. 移动端适配基础
1.1 移动端与桌面端的核心差异
维度 桌面端 移动端 输入方式 鼠标 + 键盘 触摸 + 手势 屏幕尺寸 1280-2560px 320-430px 网络 稳定宽带 4G/5G(可能不稳定) 性能 高端 CPU/GPU 中低端处理器 注意力 长时间深度使用 碎片化短时使用 上下文 办公室/家 地铁/户外/走路
1.2 Viewport 配置
Next.js App Router 中配置 viewport:
// app/layout.tsx
export const viewport : Viewport = {
width: 'device-width' ,
initialScale: 1 ,
maximumScale: 1 , // 禁止用户缩放(表单场景避免 iOS 自动缩放)
userScalable: false ,
themeColor: '#ffffff' ,
}
配置项 推荐值 说明 widthdevice-width视口宽度等于设备宽度 initialScale1初始缩放 100% maximumScale看场景 内容站允许缩放,App 型可禁止 themeColor品牌色 浏览器工具栏颜色
1.3 触摸交互设计
设计原则 说明 点击区域 ≥ 44px Apple HIG 推荐的最小触摸目标 避免 hover 依赖 移动端没有 hover 状态 手势友好 上下滑动浏览、左右滑动切换 底部导航 拇指操作区在屏幕下半部分 避免双击缩放延迟 touch-action: manipulation安全区域 适配 iPhone 刘海和底部条
1.4 安全区域适配
现代手机有刘海、挖孔、圆角等异形屏幕,需要使用 env() 函数适配:
.bottom-nav {
padding-bottom : env(safe-area-inset-bottom, 0 px );
}
.header {
padding-top : env(safe-area-inset-top, 0 px );
}
Tailwind v4 中可以用 pb-[env(safe-area-inset-bottom)] 内联使用。
2. 移动端性能优化
2.1 移动端性能预算
指标 桌面目标 移动目标 说明 LCP < 2.5s < 2.5s 移动端网络慢,需要更多优化 INP < 200ms < 200ms 移动端 CPU 慢,JS 执行更耗时 JS Bundle < 200KB < 150KB 移动端解析 JS 更慢 首屏图片 优化 WebP/AVIF + 适配尺寸 不要加载桌面尺寸的图片
2.2 响应式图片
不同设备应该加载不同尺寸的图片:
设备 屏幕宽度 图片宽度 预估大小 手机 375px 375px ~30KB 平板 768px 768px ~80KB 桌面 1280px 1280px ~150KB
Next.js <Image> 组件自动处理:
根据设备 DPR 生成 srcset
懒加载视口外的图片
自动转换为 WebP/AVIF
根据容器宽度选择最优尺寸
2.3 移动端特有的性能优化
优化 说明 减少 JS 执行量 Server Components 把逻辑移到服务端 骨架屏 Suspense fallback 替代白屏等待 预连接 preconnect 到 API 域名字体优化 font-display: swap + next/font延迟加载非关键资源 dynamic() + loading="lazy"减少动画 prefers-reduced-motion 检测
3. PWA 基础
3.1 什么是 PWA
PWA 是一种让 Web 应用具备原生 App 体验的技术集合:
能力 原生 App Web PWA 安装到主屏幕 ✅ ❌ ✅ 离线访问 ✅ ❌ ✅ 推送通知 ✅ ❌ ✅ 全屏模式 ✅ ❌ ✅ 自动更新 ✅ ✅ ✅ 应用商店 ✅ ❌ ⚠️ 部分 跨平台 ❌ ✅ ✅ 无需安装 ❌ ✅ ✅ SEO ❌ ✅ ✅
3.2 PWA 的三大要素
要素 作用 必须? HTTPS 安全环境 ✅ 必须 Web App Manifest 定义应用名称、图标、启动行为 ✅ 必须 Service Worker 离线缓存、后台同步、推送通知 ✅ 核心
3.3 PWA 在 2025 年的现状
平台 支持程度 限制 Android Chrome ⭐⭐⭐⭐⭐ 完整支持 iOS Safari ⭐⭐⭐ 推送通知支持(iOS 16.4+),但仍有限制 Windows Edge ⭐⭐⭐⭐⭐ 完整支持 macOS Safari ⭐⭐⭐⭐ Sonoma 开始支持
iOS 的限制 :
Storage 限制(50MB 缓存)
后台执行受限
推送通知需要用户从主屏幕打开
没有完整的 Web App Manifest 支持
4. Web App Manifest
4.1 Manifest 配置
Next.js App Router 中可以通过 app/manifest.ts 生成:
字段 说明 示例 name完整应用名 "My App" short_name简短名称(主屏幕图标下方) "App" start_url启动 URL "/" display显示模式 "standalone" background_color启动画面背景色 "#ffffff" theme_color主题色 "#3b82f6" icons应用图标数组 多个尺寸
4.2 显示模式
模式 效果 适用场景 browser普通浏览器 不推荐 minimal-ui最小化浏览器 UI 内容网站 standalone无浏览器 UI(像原生 App) App 型 PWA fullscreen全屏(无状态栏) 游戏
推荐 standalone ——用户感觉不到是在浏览器中运行。
4.3 图标要求
尺寸 用途 192x192 Android 主屏幕图标 512x512 Android 启动画面 180x180 iOS 主屏幕图标(apple-touch-icon) 任意 SVG 现代浏览器矢量图标
5. Service Worker
5.1 Service Worker 的作用
Service Worker 是运行在浏览器后台的 JavaScript 线程——它拦截网络请求,实现离线缓存、后台同步、推送通知。
用户请求 → Service Worker 拦截
├── 缓存命中 → 直接返回缓存(离线可用)
├── 缓存未命中 + 在线 → 请求网络 → 缓存结果 → 返回
└── 缓存未命中 + 离线 → 返回离线页面
5.2 缓存策略
策略 名称 行为 适用场景 Cache First 缓存优先 先查缓存,没有才网络 静态资源(JS/CSS/图片) Network First 网络优先 先网络,失败用缓存 API 数据、页面 HTML Stale While Revalidate 先旧后新 返回缓存,后台更新 非关键但需要新鲜的数据 Network Only 仅网络 不缓存 实时数据(支付、认证) Cache Only 仅缓存 只读缓存 构建时预缓存的资源
5.3 Next.js 的 Service Worker 方案
方案 特点 推荐度 @serwist/next Serwist(next-pwa 继任者),Workbox 底层 ⭐⭐⭐⭐⭐ next-pwa 经典方案,但维护放缓 ⭐⭐⭐ 自定义 Service Worker 完全控制 ⭐⭐⭐(需要手写) Workbox Google 出品,底层工具 ⭐⭐⭐⭐
推荐 @serwist/next ——它是 next-pwa 的现代继任者,与 App Router 兼容性最好。
5.4 预缓存 vs 运行时缓存
类型 时机 内容 优势 预缓存 安装 Service Worker 时 JS/CSS/关键页面 离线立即可用 运行时缓存 用户访问时 API 响应、图片 按需缓存,节省空间
6. 离线体验设计
6.1 离线策略
策略 说明 适用场景 离线页面 显示友好的离线提示页面 所有 PWA 最低要求 离线阅读 缓存已访问的内容 新闻、博客、文档 离线操作 允许用户操作,上线后同步 表单、任务管理 完全离线 应用核心功能离线可用 工具类 App
6.2 离线数据同步
用户离线操作(创建/修改/删除)
↓
操作存入 IndexedDB 队列
↓
网络恢复
↓
Background Sync API 触发
↓
逐个提交离线操作到服务器
↓
处理冲突(Last Write Wins / 合并)
6.3 离线 UI 反馈
状态 UI 反馈 在线 正常显示 离线 顶部 Banner 提示"当前离线" 操作排队 显示"待同步"标记 同步中 显示同步进度 同步完成 清除标记 同步失败 显示错误 + 重试按钮
7. 推送通知
7.1 Web Push 架构
服务端发送推送请求
↓
Push Service(Google FCM / Apple APNs)
↓
用户设备接收
↓
Service Worker 触发 push 事件
↓
显示系统通知
7.2 推送通知的最佳实践
实践 说明 延迟请求权限 不要一打开就弹权限请求 说明价值 告诉用户"订阅后会收到什么" 控制频率 每天不超过 2-3 条 提供退出 应用内提供取消订阅的选项 相关性 只推送用户关心的内容 及时性 推送时效性强的信息
7.3 权限请求时机
❌ 糟糕的时机 ✅ 好的时机 首次访问就弹窗 用户完成注册后 随机弹出 用户主动点击"接收通知" 无上下文 在相关场景中(如"订阅订单更新")
8. PWA 适用性评估
8.1 何时选择 PWA
✅ 适合 PWA 的场景 :
内容消费型应用(新闻、博客、文档)
轻量工具型应用(待办、记账、翻译)
电商(浏览 + 收藏 + 推送)
需要跨平台但预算有限
❌ 不适合 PWA 的场景 :
需要深度系统集成(相机高级功能、蓝牙)
高性能图形(3D 游戏)
必须在应用商店分发
iOS 用户为主(PWA 限制较多)
8.2 PWA vs 原生 App vs 混合 App
维度 PWA React Native Flutter 原生 开发成本 最低 中 中 最高 性能 良好 好 优秀 最佳 离线能力 有限 完整 完整 完整 系统集成 有限 大部分 大部分 完整 更新速度 即时 即时/商店 即时/商店 商店审核 SEO ✅ ❌ ❌ ❌ 安装门槛 几乎无 需要下载 需要下载 需要下载
本章小结
移动优先 :触摸交互 ≥ 44px 点击区域、安全区域适配、移动端性能预算更严格
响应式图片 :Next.js <Image> 自动处理 srcset、格式转换、懒加载
PWA 三要素 :HTTPS + Web App Manifest + Service Worker
缓存策略 :静态资源 Cache First,API 数据 Network First,非关键数据 Stale While Revalidate
Service Worker :推荐 @serwist/next(next-pwa 继任者)
离线设计 :操作存入 IndexedDB → 网络恢复后 Background Sync 同步
推送通知 :延迟请求权限、说明价值、控制频率
选型 :内容/工具类应用适合 PWA,需要深度系统集成的选择原生/RN/Flutter