移动端适配 是做什么的?
目标
将现有界面适配为在手机上良好运行,同时不移除核心功能。除非用户指定其他目标,否则优先针对 iPhone 级别的移动网页进行优化。
默认目标
如果用户未指定设备或浏览器,则首先针对以下环境进行优化:
- iPhone Pro Max 级别,竖屏和横屏
- iOS Safari
- 紧凑型触摸屏,宽度约
375-440 CSS px - 键盘打开状态、大文本、安全区域和减少运动
何时进行研究
此技能依赖于当前平台行为。
- 当用户要求了解最新/当前指南、iPhone 特定行为、Safari/WebKit 怪癖、安全区域行为、PWA/主屏幕行为或直接引用时,请查阅官方来源。
- 首选 Apple Developer、WebKit、W3C/WCAG、MDN、Android Developers 和 web.dev。
- 在引用最近的平台更改时,应使用绝对日期。
有关当前高信号规则和来源,请阅读 references/mobile-ui-2026.md。
核心规则
-
保持紧凑型手机为单列布局。 不要仅仅因为横屏手机跨越了通用断点就切换为桌面信息架构。旋转侧放的手机仍然是用双手在臂展距离握持的——用户的思维模型是“手机”,而不是“平板”。拆分为多列布局会产生令人困惑的体验,导致没有任何内容足够大,难以舒适使用。
-
仅对真正的一级部分使用底部优先的移动导航。 将其限制在
3-5个主要目的地;将溢出项移入更多、一个弹出面板或次要流程。屏幕底部是拇指的自然休息区——将主要导航放在那里意味着最常见的操作只需最少的努力。超过 5 个项会缩小触控目标至可用尺寸以下,并让用户难以扫描。 -
每个交互目标在两个维度上都应至少为
44x44 CSS px。 这包括容易被忽略的次要元素:内联操作按钮(编辑、删除、查看)、展开/折叠切换开关、筛选标签、工具栏中的图标按钮、弹出面板上的关闭按钮以及复选框/单选按钮行(使用<label>作为完整触控目标,而不仅仅是输入本身)。电容式触摸屏在约 44pt 处注册手指接触区域的中心——较小的目标会导致误触挫折感,尤其是在运动中。常见的 Tailwind 类不足的示例:h-8(32px)、h-9(36px)、在图标上使用p-1(~24px)、p-1.5(~28px)、p-2(~32px)。使用h-11(44px)、min-h-[44px]或等效值作为每个可点击元素的基准。这与 Apple HIG 一致,并超过了 WCAG 2.2 的 24px 最低要求。 -
不要依赖悬停、小图标点击或隐藏的行操作。 触摸设备上没有悬停状态——任何需要悬停才能发现的内容都是不可见的。使用可见的控件、带有视觉提示的滑动操作或上下文弹出面板/菜单。
-
避免水平页面滚动。 单手手机使用是垂直拇指滚动。水平滚动破坏了用户的空间模型,并将内容隐藏在屏幕外,没有可见的提示。应重新流式排列、堆叠、分页或本地滚动表格和图表,而不是整个页面。
-
使用
viewport-fit=cover、env(safe-area-inset-*)和min-height: 100dvh。 现代 iPhone 具有圆角、灵动岛和主页指示器——所有这些都会侵占矩形视口。没有明确的安全区域处理,内容会被硬件控件区域遮挡。dvh考虑到了旧版vh未能处理的 Safari 折叠工具栏。 -
使主要操作远离浏览器栏、主页指示器、圆角和屏幕键盘。 隐藏在键盘后面或与主页指示器重叠的“提交”按钮在功能上是损坏的——用户要么看不到它,要么无法在不触发系统手势的情况下点击它。
-
对于表单密集或键盘密集的流程,优先使用一个主滚动容器。 iOS Safari 上的嵌套滚动区域会产生滚动陷阱:用户的手指滚动内部容器时,原本意图滚动页面,反之亦然。WebKit 在此处存在持续的错误(请参阅参考文件)。仅在没有其他选择时才使用嵌套滚动。
-
使用语义化的移动输入。 标签位于字段上方(而不是旁边——没有水平空间)、正确的
type、inputmode、autocomplete和enterkeyhint。这些属性控制显示哪个键盘——inputmode="decimal"为货币显示数字键盘,enterkeyhint="next"允许用户在不关闭键盘的情况下在表单中跳转。 -
将大文本视为真正的布局输入。 iOS 用户可以设置系统范围的大文本,许多人确实如此。应进行换行和重新流式排列——不要将关键含义隐藏在截断之后。如果截断的标签让用户猜测他们看到的是“储蓄账户”还是“工资账户”,布局就失败了。
-
在手机上,图表辅助叙述;它们不是叙述的全部。 手机屏幕可能只能渲染大约 5-6 个可读的条形或一个甜甜圈。这不足以让图表自解释。首先显示关键数字和文本摘要;将图表用作视觉强化。
-
保留产品的现有品牌和设计系统,除非用户要求进行更广泛的重新设计。移动端适配是关于布局和交互,而不是换肤。
示例
在更改导航外壳、数据表或带有提交按钮的表单之前,请阅读 references/mobile-examples.md。其中包含侧边栏变为底部标签栏、表格变为手机上的卡片列表以及提交按钮保持在键盘上方的表单的 before/after 代码。
工作流程
- 锁定目标上下文。
- 设备、浏览器、方向、使用上下文
- 如果未指定,默认使用 iPhone Pro Max + iOS Safari
- 首先审计外壳。
- 导航模式
- 安全区域
- 粘性/固定栏
- 横屏行为
- 键盘行为
- 审计每个屏幕或组件。
- 列表和行
- 表单
- 表格
- 图表
- 空/错误/加载状态
- 选择硬切换点。
- 哪些变为单列
- 哪些变为卡片
- 哪些移入弹出面板/抽屉
- 哪些在“更多”下变为次要内容
- 实施移动优先适配。
- 组件内部优先使用容器查询
- 外壳/布局模式更改优先使用视口查询
- 除非明确要求,否则不要保留旧的半桌面/半移动行为
- 在紧凑型竖屏和紧凑型横屏上验证。
- 首先验证 Safari/WebKit
- 然后验证 Chromium
- 首先报告最高风险的问题,然后报告具体更改和任何遗留的差距。
屏幕检查清单
外壳和导航
- 保持横屏手机处于手机外壳模式。
- 避免对仍然是手机的设备进行硬性
md => 桌面侧边栏切换。 - 使用
env(safe-area-inset-bottom)为底部 UI 添加内边距。 - 使粘性操作位于底部导航上方。
- 保持移动端标签简短。
列表和行
- 允许标题、元数据和金额在需要时换行成两行。
- 为价格、余额和总计保留稳定空间。
- 优先使用堆叠的元数据而非压缩的内联元数据。
- 使用可见控件或弹出面板/菜单来暴露操作,而不是悬停。
- 将行操作按钮(编辑、删除、查看、展开)的尺寸至少设为
44x44 CSS px——不仅仅是主要导航和工具栏按钮。
表单
- 在紧凑型手机上使用单列。
- 使提交按钮保持在键盘上方可见。
- 使用清晰的全宽主要行动号召按钮。
- 将长流程分解为步骤或渐进式披露。
- 如果格式化或精度很重要,避免使用
type="number"来处理货币。
表格和导入/审核流程
- 在手机上,将密集的可编辑表格转换为卡片/列表。
- 如果必须保留真正的表格,请将水平滚动限制在表格内部。
- 确保粘性标题和工具栏不会遮挡焦点输入框。
图表和统计数据
- 首先显示关键数字和简短叙述。
- 添加紧凑的图例和文本后备。
- 优先使用水平滚动或分页比较,而不是不可读的密集条形图。
- 避免在紧凑屏幕上使用小甜甜圈图。
验证
对于下面的每个检查项,确认具体的通过条件并使用建议的工具。真实设备测试是黄金标准——模拟器对于迭代很有用,但无法完全重现键盘时序、滚动惯性或触摸精度。
-
竖屏和横屏——手机在两种方向上都保持移动外壳模式。没有布局损坏、内容溢出,也不会突然切换到桌面侧边栏或多列视图。在 375px(iPhone SE/mini 级别)、390px(iPhone Pro)和 430px(iPhone Pro Max)竖屏及其对应的横屏下测试。使用 Chrome DevTools 设备工具栏或 Xcode Simulator。
-
iOS Safari 安全区域——内容不会被灵动岛、圆角或主页指示器剪裁。底部固定元素具有可见的
env(safe-area-inset-bottom)内边距(在 Face ID iPhone 上约为 34px)。验证视口元标记中是否设置了viewport-fit=cover——如果没有设置,所有env(safe-area-inset-*)值都将返回0。最好在 Xcode Simulator(准确的每设备内边距)或 Polypane 26+(具有真实安全区域内边距预设的桌面浏览器)中测试。Chrome DevTools 135+ 支持Emulation.setSafeAreaInsetsOverride,但需要手动配置。 -
键盘打开的表单流程——按顺序聚焦每个输入并验证:(1) 焦点字段滚动到视图中,(2) 提交操作可见且可点击,(3) 粘性标题不会遮挡焦点字段。请注意,
position: fixed; bottom: 0元素会隐藏在 iOS 键盘后面(布局视口不会缩小),并且position: sticky; bottom: 0在键盘显示期间也无法固定(WebKit bug #202120)。Playwright 和 Cypress 无法触发真实的屏幕键盘——这需要真实设备测试或带有 Safari Web Inspector 的 Xcode Simulator。 -
大文本/显示缩放——WCAG 1.4.4 (AA) 要求文本可调整到 200% 而不丢失内容。WCAG 1.4.10 (AA) 要求在 400% 缩放(相当于 320px 宽的视口)下重新流式排列,而不会出现水平滚动。测试方法:(1) 将浏览器缩放设置为 200% 并验证没有截断或重叠,(2) 将视口设置为 1280px 并放大至 400% 以模拟 320px 重新流式排列要求,(3) 启用 iOS 设置 > 辅助功能 > 显示与文字大小 > 更大字体至最大。验证视口元标记未设置
user-scalable=no或maximum-scale低于 2.0。 -
减少运动——动画尊重
prefers-reduced-motion: reduce。过渡仍然传达状态变化,但使用交叉淡入淡出或不透明度而不是运动。iOS Safari 在开启“减少运动”时不会自动抑制 Web 动画——开发者必须自行处理。通过以下方式测试:Chrome DevTools 渲染选项卡 > “模拟 prefers-reduced-motion”、Safari Web Inspector 偏好覆盖(自 2022 年末起可用)或 Playwright 的page.emulateMedia({ reducedMotion: 'reduce' })。 -
空/错误/加载状态——这些状态在紧凑屏幕上正确渲染。加载骨架匹配移动布局,而不是桌面布局。错误消息无需滚动即可阅读。
-
独立/PWA 模式(相关时)——如果应用支持
display: standalone,请验证状态栏区域、主页指示器和手势区域是否已处理。svh和dvh在独立模式下解析为相同的值,因为没有可折叠的工具栏(WebKit bug #261185)。WebKit bug #254868 可能导致错误的高度值。WebKit bug #265578 导致当 Safari UI 动画回到视图时,视觉视口高度更新延迟。 -
没有水平文档滚动——在页面主体上左右滑动不会产生任何移动。任何水平滚动都隔离到特定容器(表格、轮播),具有可见的溢出提示和
overscroll-behavior: contain,以防止触发 Safari UI 偏移(WebKit bug #240861)。对于 Playwright 中的自动验证:const hasOverflow = await page.evaluate(() => document.documentElement.scrollWidth > document.documentElement.clientWidth ); expect(hasOverflow).toBe(false);
交付物
使用此技能时,应生成:
- 一个简短的移动端适配计划
- 首先列出最高风险的问题
- 具体的每屏幕更改
- 已执行的验证
- 任何剩余的设备/浏览器不确定性