关于 mobile-ui-design
为构建移动界面提供设计指导,面向生成或实现移动端 UI 的 Agent。内容涵盖触控、导航、安全区域、表单、动效及渲染检查,并强调无障碍与不同平台模式。
主要功能
- 01加载设计上下文并映射设计令牌
- 02触控目标与底部导航规范
- 03手势、安全区域及平台模式指导
- 04移动端排版与表单建议
- 05动效、无障碍及渲染检查
适用场景
- 01设计移动端导航与交互布局
- 02实现适配安全区域的页面
- 03检查移动表单和触控目标
- 04生成界面后验证不同视口
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ arnavpuri/ designskills --skill mobile-ui-design安装后在 Claude Code 中输入/mobile-ui-design确认已加载。
详细介绍
移动端 UI 设计
开始之前:加载设计上下文
- 阅读
.agents/design-context.md(由design-context技能编写)。如果文件不存在,请在tailwind.config.*或:rootCSS 变量中查找设计令牌。如果都没有,请使用默认值(主色#2563EB、辅助色#7C3AED、强调色#F59E0B、Tailwind 灰色中性色、标题和正文使用 Inter、极简风格),并告知用户使用了默认值——建议运行design-context。 - 将设计令牌映射为 CSS 变量一次,之后只使用这些变量:
--color-primary、--color-primary-light、--color-primary-dark、--color-secondary、--color-accent、--color-neutral-50…--color-neutral-900、--color-success/-warning/-error、--font-heading、--font-body、--font-mono、--radius,以及以 4px 为基准的间距刻度。 - **Tailwind:**以
primary、primary-light、primary-dark、secondary、accent、neutral-*、font-heading、font-body为名,公开相同的变量(v3 使用theme.extend,v4 使用@theme)。下方示例中的indigo-*/gray-*类是这些设计令牌的占位符。 - **Figma:**如果用户提供 Figma URL,请使用 Figma MCP(
get_design_context、get_screenshot)获取设计并与之匹配;对于该设计,它优先于上下文文件。 - 询问这是原生应用(React Native/Flutter:将设计令牌映射到主题对象,而不是 CSS 变量)、PWA,还是响应式网站。
1. 触控目标尺寸
每个可交互元素都必须足够大,确保用户能够可靠地点击。
最小尺寸
| 来源 | 最小目标尺寸 | 备注 |
|---|---|---|
| Apple HIG | 44×44pt | = 网页上的 44×44 CSS px |
| Material Design | 48×48dp | ≈ 48×48 CSS px;图标视觉尺寸可以是 24dp |
| WCAG 2.2 SC 2.5.8 (AA) | 24×24 CSS px | 法律规定的底线,而非设计目标 |
| WCAG 2.2 SC 2.5.5 (AAA) | 44×44 CSS px |
**此技能的规则:**所有触控目标至少为 44×44px(Android 风格 UI 中为 48×48px)。
实现
/* Ensure tap targets even on small visual elements */
.icon-button {
width: 24px;
height: 24px;
/* Expand tap target with padding or pseudo-element */
position: relative;
}
.icon-button::after {
content: '';
position: absolute;
inset: -12px; /* extends tap area to 48x48 */
}
目标之间的间距
可点击元素之间至少留出 8px 的间隙,建议为 12px 或更大,以避免误触。
2. 底部导航
拇指最容易触及屏幕底部,因此应将主要导航放在那里。
标准底部标签栏
<nav aria-label="Main" class="fixed bottom-0 inset-x-0 bg-white border-t border-gray-200
safe-area-bottom z-50">
<div class="flex items-center justify-around h-16">
<a href="#" aria-current="page" class="flex flex-col items-center justify-center gap-0.5
text-indigo-600 min-w-[64px] min-h-[48px]">
<svg class="w-6 h-6" fill="currentColor" aria-hidden="true"></svg>
<span class="text-xs font-medium">Home</span>
</a>
<a href="#" class="flex flex-col items-center justify-center gap-0.5
text-gray-500 min-w-[64px] min-h-[48px]">
<svg class="w-6 h-6" fill="none" stroke="currentColor" aria-hidden="true"></svg>
<span class="text-xs font-medium">Search</span>
</a>
</div>
</nav>
规则
- 最多 5 个标签。3–4 个最理想。
- 当前标签:实心图标 + 主色。非当前标签:线框图标 + 灰色。
- 必须显示标签文字。仅使用图标的标签不易被用户发现。
- 绝不要用汉堡菜单替代标签栏。
- 在带刘海的设备上,需考虑底部安全区域。
安全区域 CSS
/* Only for elements with no bottom padding of their own */
.safe-area-bottom {
padding-bottom: env(safe-area-inset-bottom);
}
/* Elements that already have padding: ADD the inset, don't replace the padding */
.pb-safe-4 {
padding-bottom: calc(1rem + env(safe-area-inset-bottom));
}
还要为可滚动内容添加内边距(例如在 <main> 上使用 pb-[calc(4rem+env(safe-area-inset-bottom))]),避免最后一项被标签栏遮挡。
3. 适合手势操作的交互
滑动操作
<div class="relative overflow-hidden">
<div class="absolute inset-y-0 right-0 flex items-center bg-red-600 px-6">
<button type="button" class="text-white font-medium">Delete</button>
</div>
<div class="bg-white px-4 py-3 transform transition-transform touch-pan-y">
<div class="font-medium text-gray-900">List Item</div>
<div class="text-sm text-gray-500">Swipe left for actions</div>
</div>
</div>
下拉刷新
- 用户下拉时,在顶部显示指示器。
- 使用旋转指示器或自定义动画。
- 下拉距离约为 80px 时触发刷新。
- 如可行,应提供触觉反馈(仅限原生应用)。
- 在网页上,为滚动容器设置
overscroll-behavior-y: contain,以防浏览器自身也触发下拉刷新。
常见移动端手势
| 手势 | 使用场景 | 实现方式 |
|---|---|---|
| 向左/向右滑动 | 显示操作、导航 | touch-action: pan-y |
| 下拉 | 刷新内容 | 过度滚动检测 |
| 长按 | 上下文菜单、重新排序 | pointerdown + 约 500ms 超时,在 pointermove/pointerup 时取消 |
| 捏合 | 缩放图片/地图 | 在可缩放元素上设置 touch-action: none + Pointer Events |
| 向上滑动 | 收起面板、展开 | 底部面板上的拖动把手 |
在按钮和链接上设置 touch-action: manipulation 可消除双击缩放延迟,但不会启用自定义捏合处理。每种手势都必须提供一个可见的单击替代方式(按钮、菜单项)——WCAG 2.5.1 和可发现性都要求这样做。
4. iOS 与 Android 的设计语言
主要差异
| 元素 | iOS(Human Interface) | Android(Material) |
|---|---|---|
| 导航 | 底部标签栏 | 底部导航栏 |
| 返回 | 从左侧边缘滑动/文本“Back” | 左上角箭头图标 |
| 标题 | 可折叠的大标题 | 居中或左对齐 |
| 按钮 | 圆角矩形,无阴影 | 圆角,带阴影 |
| 开关 | 绿色/白色切换开关 | 轨道 + 滑块,带涟漪效果 |
| 底部弹层 | 顶部圆角,带拖动手柄 | 全宽,带拖动手柄 |
| 字体 | SF Pro(系统字体) | Roboto(系统字体) |
| 间距 | 16px 边距 | 16px 边距 |
跨平台方案
同时面向两个平台构建时,精致度方面倾向采用 iOS 模式,交互反馈方面倾向采用 Material 模式。使用系统字体:
/* Use the design-context body font if set; otherwise the platform font */
font-family: var(--font-body, system-ui), -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
5. 安全区域
设备注意事项
/* Status bar area */
.top-safe {
padding-top: env(safe-area-inset-top);
}
/* Home indicator / gesture bar */
.bottom-safe {
padding-bottom: env(safe-area-inset-bottom);
}
/* Notch / Dynamic Island on landscape */
.side-safe {
padding-left: env(safe-area-inset-left);
padding-right: env(safe-area-inset-right);
}
/* Full-bleed safe wrapper */
.safe-area {
padding: env(safe-area-inset-top) env(safe-area-inset-right)
env(safe-area-inset-bottom) env(safe-area-inset-left);
}
Viewport Meta
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
viewport-fit=cover 是必需的,否则 env(safe-area-inset-*) 返回的值将为零。切勿添加 maximum-scale=1 或 user-scalable=no,这会阻止双指缩放(WCAG 1.4.4)。
视口高度
显示移动浏览器工具栏时,100vh 会高于可见区域。全屏应用外壳和底部弹层使用 100dvh(会随工具栏变化),滚动时不应调整大小的首屏区域使用 100svh(Tailwind:h-dvh、h-svh)。
6. 移动端字体大小规范
推荐规范
| 角色 | 大小 | 字重 | 行高 |
|---|---|---|---|
| 大标题 | 34px | 700 | 1.2 |
| 标题 1 | 28px | 700 | 1.2 |
| 标题 2 | 22px | 700 | 1.25 |
| 标题 3 | 20px | 600 | 1.25 |
| 主标题 | 17px | 600 | 1.3 |
| 正文 | 17px | 400 | 1.5 |
| 提示文字 | 16px | 400 | 1.4 |
| 副标题 | 15px | 400 | 1.4 |
| 脚注 | 13px | 400 | 1.3 |
| 说明文字 | 12px | 400 | 1.3 |
规则
- 为确保易读性,移动端正文最小字号为 16px。
- 输入框、选择框和文本区域的字号必须 ≥16px——iOS Safari 会自动放大字号较小的字段。
- 行长:最多 35–50 个字符,以便在移动设备上舒适阅读。
- 使用基于 16px 根字号的
rem单位。
7. 拇指触控区域优化
拇指触控区域示意图
+-----------------------------+
| Hard to reach | <- Top 25%: Put secondary actions, titles
| |
|-----------------------------|
| Comfortable stretch | <- Middle 50%: Content, scrollable lists
| |
|-----------------------------|
| Easy / Natural | <- Bottom 25%: Primary actions, nav, FAB
+-----------------------------+
实用规则
- 主要操作放在底部:CTA 按钮、提交按钮、导航。
- 搜索栏:考虑放在底部(类似 iOS Safari)。
- FAB(浮动操作按钮):放在右下角,尺寸为 56px,并带阴影。
- 破坏性操作放在顶部:越难触及,就越难误触。
<div class="fixed bottom-0 inset-x-0 px-4 pt-12 pb-safe-4 bg-gradient-to-t from-white via-white
to-transparent">
<button type="button" class="w-full bg-indigo-600 text-white py-4 rounded-2xl font-semibold
text-lg active:bg-indigo-700 transition-colors">
Continue
</button>
</div>
8. 底部弹层/底部抽屉模式
底部弹层结构
<div class="fixed inset-0 z-50">
<div class="absolute inset-0 bg-black/40 backdrop-blur-sm" data-dismiss></div>
<div role="dialog" aria-modal="true" aria-labelledby="sheet-title"
class="absolute bottom-0 inset-x-0 bg-white rounded-t-3xl
max-h-[85dvh] overflow-y-auto overscroll-contain pb-safe-4">
<div class="flex justify-center pt-3 pb-2" aria-hidden="true">
<div class="w-10 h-1 rounded-full bg-gray-300"></div>
</div>
<div class="px-4 pb-6">
<div class="flex items-center justify-between mb-4">
<h2 id="sheet-title" class="text-xl font-bold text-gray-900">Sheet Title</h2>
<button type="button" aria-label="Close" class="w-11 h-11 -mr-2 rounded-full
flex items-center justify-center text-gray-500">✕</button>
</div>
</div>
</div>
</div>
弹层变体
- 预览弹层:显示 30% 的内容,拖动即可展开。
- 操作弹层:选项列表(iOS 风格)。
- 全屏弹层:向上滑动并覆盖整个屏幕,带关闭按钮。
- 地图弹层:覆盖在地图上的常驻底部弹层(Google Maps 风格)。
弹层规则
- 始终包含拖动手柄(宽 40px、高 4px、居中、圆角)。
- 最大高度:视口的 85%。允许在内部滚动。
- 关闭方式:向下滑动、点击背景或使用明确的关闭按钮。
- 吸附位置:折叠、半展开、展开。
9. 移动端表单设计
规则
- 大尺寸输入框:最小高度为 48px,字号为 16px 及以上(避免 iOS 缩放)。
- 全宽输入框:在容器内从一侧边缘延伸到另一侧边缘。
- 智能键盘类型:使用
inputmode属性。 - 固定提交按钮:固定在屏幕底部。
- 仅使用单列:移动端切勿并排放置字段。
Input Mode 属性
<input type="tel" inputmode="tel" />
<input type="email" inputmode="email" />
<input type="text" inputmode="numeric" pattern="[0-9]*" />
<input type="url" inputmode="url" />
<input type="search" inputmode="search" />
针对移动端优化的输入框
<div class="space-y-1.5">
<label for="phone" class="block text-sm font-medium text-gray-700">
Phone number
</label>
<input
type="tel"
id="phone"
inputmode="tel"
autocomplete="tel"
class="block w-full h-12 rounded-xl border border-gray-300 px-4
text-base text-gray-900 placeholder:text-gray-400
focus:border-indigo-500 focus:ring-2 focus:ring-indigo-500/20"
placeholder="+1 (555) 000-0000"
/>
</div>
10. 原生感动画
时间函数
:root {
/* iOS-like spring curve (slight overshoot) */
--ease-spring: cubic-bezier(0.175, 0.885, 0.32, 1.275);
/* Quick in, slow out (for entering elements) */
--ease-out: cubic-bezier(0.16, 1, 0.3, 1);
/* Slow in, quick out (for exiting elements) */
--ease-in: cubic-bezier(0.55, 0, 1, 0.45);
}
常见过渡效果
/* Page transition: slide from right */
.page-enter {
transform: translateX(100%);
animation: slide-in 350ms var(--ease-out) forwards;
}
@keyframes slide-in {
to { transform: translateX(0); }
}
/* Sheet reveal: slide up */
.sheet-enter {
transform: translateY(100%);
animation: sheet-up 400ms var(--ease-out) forwards;
}
@keyframes sheet-up {
to { transform: translateY(0); }
}
/* Tap feedback */
.tap-feedback:active {
transform: scale(0.97);
opacity: 0.8;
transition: transform 50ms ease, opacity 50ms ease;
}
移动端动画规则
- 动画时长控制在 400ms 以内。200–300ms 会显得灵敏。
- 仅使用
transform和opacity,以确保 60fps 性能。 - 对动画元素谨慎添加
will-change: transform。 - 遵循
prefers-reduced-motion:
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
- 为重要操作提供触觉反馈(仅原生应用)。
验证:渲染并检查
不要交付未经检查的代码。生成代码后:
- 在手机和桌面宽度下截图,例如运行
npx playwright screenshot --full-page --viewport-size=390,844 file://$PWD/index.html mobile.png,然后再用--viewport-size=1440,900截图(或使用开发服务器 URL)。 - 打开两张图片并检查:没有水平滚动,也没有文字被裁切或重叠;层级一目了然;已应用品牌设计令牌;图片按正确的宽高比加载。
- 用 Tab 键依次浏览一次:每个交互元素都显示可见的焦点环,顺序符合逻辑。
- 还要在 320px 宽度和横屏模式下截图;固定栏必须避开安全区域。无头浏览器不会模拟刘海,因此请在代码中确认每个固定的顶部/底部栏都添加了
env(safe-area-inset-*)(如果有 iOS Simulator,也可以在那里检查)。 - 修复发现的问题,并在报告完成前重新截图。
移动端设计检查清单
- 所有点击目标均至少为 44×44px(Material 设计要求为 48×48),绝不低于 WCAG 的 24×24
- 底部导航包含 3–5 个带标签的选项卡
- 遵循安全区域要求(顶部、底部、两侧)
- 正文至少为 16px(聚焦时不会触发 iOS 缩放)
- 主要操作位于拇指易触达区域(底部)
- 表单使用正确的
inputmode属性 - 底部弹层带有拖动把手和关闭手势
- 动画时长低于 400ms,并使用 GPU 友好型属性
- 已设置
viewport-fit=cover元标签;未禁用缩放 - 全高布局使用
dvh/svh,而非100vh - 每种手势都有点击替代方式;底部弹层标记为对话框并进行焦点管理
- 遵循
prefers-reduced-motion设置 - 内容在 320px 宽度下清晰易读
- 所有屏幕均无水平滚动
- 已在 320px、390px 和横屏模式下渲染并截图(参见“验证”)