关于 mobile-feel
mobile-feel 是一份面向移动网页设计与开发的技能指南,覆盖触控、视口、输入、布局和性能等细节,帮助按手机使用情境检查界面。
主要功能
- 01触控目标与手势建议
- 02视口和安全区域处理
- 03键盘与表单输入建议
- 04底部面板及导航模式
- 05滚动、反馈与性能检查
适用场景
- 01检查手机界面的触控尺寸和布局
- 02调整键盘弹出时的输入框位置
- 03规划底部面板和导航交互
- 04测试移动网页的滚动与加载体验
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ paragonhq/ stealth-skills --skill mobile-feel安装后在 Claude Code 中输入/mobile-feel确认已加载。
详细介绍
移动端体验
手机不是小屏幕桌面。指针是拇指,视口会移动,键盘会占据半个屏幕,每次误触都能真切地感受到。
目标
- 所有可点按的元素至少为 44×44px,即使它实际只显示为 20px。通过内边距或伪元素扩大点击区域,而不是放大图标。
- 相邻点击目标之间至少间隔 8px。
- 主要操作放在屏幕下方三分之一处,也就是拇指自然停留的位置。破坏性操作放在远离该区域的位置。
- 可点击目标应是整行,而不是行内的文字。
视口
- 使用
100dvh,绝不使用100vh。vh包含浏览器界面;dvh才是实际可见的区域。对于浏览器界面隐藏时不应调整大小的元素,使用svh。 <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">。viewport-fit=cover可启用安全区内边距。绝不使用user-scalable=no或maximum-scale=1。- 所有固定或粘性边缘元素都要考虑安全区:
.bottom-bar { padding-bottom: max(12px, env(safe-area-inset-bottom)); }
.top-bar { padding-top: env(safe-area-inset-top); }
触控行为
* { -webkit-tap-highlight-color: transparent; }
button, a, [role="button"] { touch-action: manipulation; } /* no 300ms delay, no double-tap zoom */
.drag-handle { touch-action: none; } /* only on the handle */
.scroll-region { overscroll-behavior: contain; -webkit-overflow-scrolling: touch; }
- 移除点按高亮后,要用自己的
:active状态替代,否则点按时会感觉毫无反应。 - 在触控设备上,点按后
:hover样式会一直保留。务必用@media (hover: hover)限定所有悬停样式。 - 在没有
touchstart监听器的元素上,iOS 的:active不可靠;使用pointerdown设置数据属性,并在pointerup/pointercancel时清除,更为可靠。 - 长按会选择文本,并在链接上显示快捷菜单;仅对控件使用
-webkit-touch-callout: none和user-select: none,绝不要对内容使用。
输入框
- 输入框的字号至少为 16px,否则 iOS 会在聚焦时缩放页面,之后也不会缩回去。
- 设置
inputmode="numeric"、"email"、"tel"、"decimal"、"search",以显示合适的键盘。 - 设置
autocomplete值(email、one-time-code、cc-number……)。用户名和代码使用autocapitalize="none"。 - 在最后一个输入框上设置
enterkeyhint="send"/"search"/"done"。 - 聚焦的输入框必须在键盘上方可见。监听
visualViewport的resize事件并将输入框滚动到视野内,或者将输入栏锚定到visualViewport.height。 - 在 iOS 上,键盘弹出时固定元素会移动。必须保持位置不变的元素,应在尺寸设为视觉视口大小的容器内使用
position: absolute。
面板
底部面板就是手机上的对话框:
- 拖动关闭,并以 1:1 的比例跟随手指移动。松手时,若拖动超过约 35% 或向下速度足够快,则关闭;否则回弹。
- 在内容自然停留的位置设置吸附点(预览、半屏、全屏)。
- 背景遮罩的不透明度随拖动变化。
- 只有在面板完全展开时,才允许在面板内滚动;在此之前,拖动应移动面板,而不是滚动内容。
- 锁定 body 滚动,且不引发布局偏移。
- 顶部设置一个 36×5px 的拖动指示条,颜色为
--fg-4。 - 使用已解决物理效果问题的库(Vaul),而不是自行编写。
手机上的全屏对话框从底部滑入;桌面上则在居中位置淡入。这是同一个组件的两种呈现方式。
底部导航
- 设置 3–5 个项目,包含图标和标签;高度为 49–56px,另加安全区高度。
- 当前项目使用
--fg,其他项目使用--fg-3。不要使用强调色填充。 - 点按当前项目时,将其视图滚动到顶部。
- 向下滚动时隐藏;只有当内容需要腾出空间时,才在向上滚动时重新显示,否则保持显示。
滚动
- 尽可能让每个屏幕只有一个滚动区域。在手机上,嵌套滚动很容易让人陷入困境。
- 下拉刷新:要么正确实现,要么在滚动容器上设置
overscroll-behavior-y: contain,以阻止浏览器触发下拉刷新。 - 水平轮播:使用
scroll-snap-type: x mandatory、为边距设置scroll-padding,并明确提示后面还有内容。 - 粘性页眉高度应低于 56px。更高会挤占屏幕空间。
- 触控设备上不要使用平滑滚动库。原生惯性滚动才是基准,不要与之争抢。
反馈
- 触屏上的按压状态应比桌面端更明显:缩放设为 0.96 而非 0.98,或使用可见的填充效果,因为没有悬停状态来让眼睛提前做好准备。
- Web 上无法使用触觉反馈(
navigator.vibrate仅适用于 Android,且效果较弱)。应在同一帧内用视觉反馈补偿。 - Toast 应显示在底部中央,位于底栏和键盘上方。
- 加载指示器应靠近拇指,而不是放在拇指遮挡的屏幕顶部。
375px 布局
- 两侧边距为 16px。不能为 0,也不能达到 24px 或更大。
- 单列布局。卡片应铺满宽度并使用 12px 圆角,或采用带分隔线的通栏行;不要同时使用两种样式。
- 正文为 15–16px,次要文本为 13px。手机拿在一臂远时,13px 的正文太小。
- 表格改为卡片,或使用水平滚动并固定首列。绝不能把表格挤扁。
- 少截断,多换行。手机上的名称换成两行显示。
- 使用最大动态字体设置和 200% 缩放进行测试。
真机性能
- 使用中端 Android 设备测试,而不是最新款 iPhone。可在 DevTools 中将 CPU 限速 4× 作为参考。
- 如果滚动卡顿,优先移除
backdrop-filter和大型盒阴影。 - 仅为
transform和opacity添加动画。在手机上绝不要为height、width或top添加动画。 - 使用适配设备尺寸的图片(
srcset),首屏以下的图片延迟加载,并异步解码。 - 在 4G 下确保 2s 内可进行首次交互:延后加载首屏以外的所有内容。
PWA 细节
- 使用
manifest.webmanifest,包含名称、图标(192、512、maskable)、display: standalone、theme_color和background_color。 - 设置
apple-mobile-web-app-capable和状态栏样式。 - 启动画面颜色应与应用框架颜色相符,而不是白色。
检查清单
- 点击目标为 44px,间距为 8px,主要操作放在屏幕下方
- 使用
dvh、viewport-fit=cover,并为固定边缘设置安全区域 - 移除点击高亮,并改用
:active状态 - 对悬停状态进行条件限制;点击后不保留悬停状态
- 输入框使用 16px,并设置
inputmode、autocomplete、enterkeyhint - 聚焦的字段在键盘上方可见
- 抽屉支持拖动和吸附,并锁定 body 滚动
- 仅有一个滚动区域;限制过度滚动
- Toast 显示在底栏上方
- 在中端 Android 设备上启用限速进行测试
目录精选
- loadmo.re — 值得参考的移动优先网站和实验项目。
- Vaul — 手势交互已解决的抽屉。
- Apple Human Interface Guidelines — Apple 对点击目标、抽屉和安全区域的规范。
- Mobbin — 可按模式搜索的真实移动端流程。
- web.dev — INP、视口单位和触屏指南。
- 更多内容参见 stealth.pm/look。
评论
支持 Markdown