mcpField
D
defaults

defaults

github.com/playful-design设计与 UI1685 次安装1 周前更新
代码仓库

关于 defaults

Defaults 是定义界面通用规范的技能,涵盖表面、导航、表单、加载状态、无障碍等常见细节。它为开发者提供具体检查项和实现指导,帮助不同屏幕保持一致行为。

主要功能

  1. 01表面、阴影与滚动规则
  2. 02焦点、键盘和触控指导
  3. 03表单输入与验证规范
  4. 04加载及更新反馈模式
  5. 05响应式与无障碍检查

适用场景

  1. 01审查界面通用默认规范
  2. 02检查表单和加载状态
  3. 03核对键盘、触控与焦点行为
  4. 04避免长内容引发的布局问题

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/playful-design/router --skill defaults

安装后在 Claude Code 中输入/defaults确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

LICENSE
recipes.md
agents/
openai.yaml

详细介绍

默认值

此技能包含适用于每个屏幕的界面默认值,涵盖表面、字体、声音、焦点、表单、加载和叠加层。

先用令牌,再用这些值

以下各项有对应值时,请使用项目的令牌。没有对应令牌时,这里的值就是精确值。硬切断滚动内容或阴影被裁切,在任何样式下都属于问题。

文字和标点属于 copy。使用项目的基础组件构建这些内容属于 reuse。是否应该存在声音或动画属于 restraint。元素的移动方式属于 motion,颜色和对比度属于 color。同心圆角、视觉微调和图标对齐属于 alignment。

滚动边缘渐隐

滚动容器的两端使用 mask-image 渐变实现渐隐。溢出边缘处硬切断属于 defaults-fade-not-cut。具体做法见 recipes.md。

阴影绝不裁切

为滚动容器留出足够的内边距,使子元素的阴影能完整显示在容器内。被 overflow: hidden 裁切的阴影属于 defaults-no-clipped-shadow。参见 recipes.md。

代码和表格横向滚动,绝不换行

代码块和数据表应横向滚动,并隐藏滚动条。代码行发生换行属于 defaults-scroll-not-wrap。参见 recipes.md。

叠加层保留滚动

可滚动的对话框、抽屉、菜单和侧面板应设置 overscroll-behavior: contain。列表滚动到底时导致其后的页面滚动,属于 defaults-contain-overscroll。

粘性界面元素保留边缘

粘性页眉或页脚应在滚动内容一侧设置 1px 边框。没有边框的粘性页眉属于 defaults-sticky-border。

将 scroll-padding-block-start 设置为粘性页眉的高度,确保锚点和获得焦点的字段显示在页眉下方。获得焦点的字段被页眉遮挡,属于 defaults-clear-sticky-chrome。

浮动表面使用环形描边,而非边框

浮动的弹出层、菜单或卡片应在阴影堆栈内配合一圈半透明的 1px 描边。阴影旁设置不透明的 border,属于 defaults-ring-not-border。在环形描边下保留 border: 1px solid transparent,以便强制颜色模式仍能显示边缘。

阴影应分层并朝一个方向投射

使用项目的 elevation 令牌。如果没有,则叠加三层阴影:模糊半径逐渐增大、不透明度逐渐降低,且全部向下偏移。只使用一个 0 4px 16px rgba(0, 0, 0, 0.2) 属于 defaults-layered-shadows。参见 recipes.md。

若要在悬停时抬高表面,应让承载抬高后阴影的伪元素渐显。对 box-shadow 添加过渡属于 defaults-fade-the-shadow。参见 recipes.md。

内容图片添加浅色轮廓

照片和屏幕截图应添加 1px 轮廓,向内缩进 1px;浅色模式下为 10% 黑色,深色模式下为 10% 白色。照片边缘与卡片融为一体,属于 defaults-image-outline。徽标和透明插图除外。参见 recipes.md。

卡片绝不嵌套

卡片绝不能置于另一张卡片内。将标题放在外部,让一个表面容纳内容。卡片内嵌卡片属于 defaults-no-nested-cards。

圆角,不用胶囊形

按钮和标签应使用圆角令牌。border-radius: 9999px 属于 defaults-rounded-not-pill。

不加装饰

移除装饰性渐变、光晕、模糊和深度效果。卡片后方的光晕属于 defaults-no-decoration。

主题应延伸至浏览器

深色主题应在根元素上设置 color-scheme: dark,让滚动条和原生控件与之保持一致。深色页面上出现浅色滚动条,属于 defaults-color-scheme。每种配色方案都应设置一个 theme-color 标签,使其与页面顶部颜色一致。

切换主题时,应关闭一帧的过渡效果。切换主题时所有颜色同时渐变,属于 defaults-quiet-theme-switch。参见 recipes.md。

仅为键盘操作显示焦点环

使用带有 outline 的 :focus-visible。每次点击都显示焦点环,属于 defaults-focus-keyboard-only。

对话框会控制焦点

对话框打开时会将焦点移入其中,按 Tab 键时焦点会留在对话框内,关闭时则将焦点还给触发它的元素。对话框打开时焦点仍留在后方页面上,属于 defaults-trap-and-return-focus。使用 showModal() 打开的原生 <dialog> 会处理焦点限制。

目标至少为 24px

每个交互目标较短的一边至少为 24px,并以鼠标操作时达到 40px、触屏操作时达到 44px 为目标。图标较小时,使用带负向内缩值的伪元素扩展点击区域。16px 图标按钮只有 16px 点击区域,属于 defaults-hit-area。扩展的点击区域绝不重叠。参见 recipes.md。

控件要说明自身用途

只有图标的按钮应带有说明其功能的 aria-label。没有名称的纯垃圾桶图标属于 defaults-name-icon-buttons。

状态不能只靠颜色表示。应搭配图标或文字。只用红点表示错误属于 defaults-not-color-alone。

链接就是链接

导航使用 <a href>,因此在新标签页中打开、中键点击和复制链接都能正常使用。通过 onClick 更改路由的 div 属于 defaults-links-are-links。

状态保存在 URL 中

筛选条件、标签页、分页和打开的面板都会写入 URL,因此刷新、分享和使用“后退”时都能保留状态。刷新后丢失的筛选条件属于 defaults-state-in-url。

缩放功能保持开启

视口标签中绝不设置 maximum-scale=1 或 user-scalable=no。阻止双指缩放的页面属于 defaults-allow-zoom。

点击体验符合原生习惯

在根元素上设置一次 -webkit-tap-highlight-color: transparent,并为每个可点击元素设置自己的 :active 状态。在触屏上点击后仍停留的灰色闪烁效果属于 defaults-no-tap-highlight。

按钮和链接设置 touch-action: manipulation,让点击无需等待第二次点击即可触发。延迟 300ms 才响应的点击属于 defaults-fast-tap。参见 recipes.md。

悬停样式需要悬停指针

将仅用于悬停的样式放在 @media (hover: hover) and (pointer: fine) 中,否则它们会在触屏上保持启用状态。点击后仍保持上浮状态的卡片属于 defaults-hover-capable-only。

全高布局使用动态单位

应用外壳或固定在底部的栏使用 100dvh,首屏使用 min-height: 100svh。底部按钮被 URL 栏遮挡的 100vh 外壳属于 defaults-dynamic-viewport。

内容避开刘海区域

在视口标签中添加 viewport-fit=cover,然后使用 env(safe-area-inset-*) 为固定页眉、标签栏、提示框和面板添加内边距。位于主屏幕指示条下方的底部栏属于 defaults-safe-areas。

控件不可选中

按钮、标签页、芯片和拖动手柄设置 user-select: none,这样长按时不会选中其标签。内容文本仍可选中。长按后高亮的按钮标签属于 defaults-controls-not-selectable。

快捷键不在输入框中触发

输入框、文本区域或可编辑元素获得焦点时,快捷键不会触发。这属于 defaults-keys-ignore-inputs。参见 recipes.md。

按 Enter 键提交

表单只有一个字段时,或焦点位于表单最后一个字段时,按 Enter 键即可提交。在文本区域中,按 Enter 键会换行,按 ⌘ 或 Ctrl 加 Enter 则会提交。需要点击才能提交的搜索框属于 defaults-enter-submits。

字段接受用户粘贴的内容

字段应接受用户实际输入或粘贴的内容,例如银行卡号中的空格或电话号码中的括号。在代码中去除格式,并清晰地显示值。拒绝 +1 (555) 010-2030 的电话号码字段属于 defaults-accept-messy-input。绝不阻止粘贴,并去除某些键盘自动添加的末尾空格。

字段选择正确的键盘

每个字段都设置 type、inputmode 和 autocomplete,以匹配相应的键盘和自动填充功能。将电子邮件字段设为纯文本类型属于 defaults-input-types。

在移动设备上,输入框应以 16px 或更大的字号显示,否则 iOS 会在输入框获得焦点时缩放页面。手机上使用 14px 输入框属于 defaults-input-16px。

标签共享点击区域

每个控件都有标签,点击标签即可操作控件。点击文本不起作用的复选框对应 defaults-label-hit-area。

表单在提交时验证

请求开始前,提交按钮始终保持启用。提交时,在每个字段旁显示对应错误,并聚焦第一个错误字段。表单有效前一直禁用的提交按钮对应 defaults-validate-on-submit。

忙碌状态的按钮保留标签

请求运行期间,按钮保留原有标签,显示指示器并禁用自身。用微调图标替换标签、导致按钮缩小的情况对应 defaults-loading-button。

危险操作可以撤销

危险操作后提供撤销选项。如果无法撤销,则在原处通过菜单或弹出框进行确认。既没有撤销选项也没有确认方式的删除操作对应 defaults-undo-destructive。

数字对齐

价格、计数、计时器和表格列使用 font-variant-numeric: tabular-nums。计数器随数值变化而宽度抖动的情况对应 defaults-tabular-numbers。

标题平衡排布,段落优雅换行

标题使用 text-wrap: balance,正文段落使用 text-wrap: pretty。标题最后一行只剩一个词的情况对应 defaults-balanced-wrap。

文本清晰呈现

在根元素上设置一次 -webkit-font-smoothing: antialiased 和 -moz-osx-font-smoothing: grayscale。缺少平滑设置,或在每个组件中分别设置,对应 defaults-antialiased-root。

行内代码字号更小

正文中的等宽字体缩小至 0.9em。行内代码仍保持完整字号、高出所在句子的情况对应 defaults-inline-mono。

截断文本可以查看完整内容

用户需要查看的截断文本,应能通过工具提示、展开控件或详情视图查看完整内容。被截断且无法查看完整内容的文件名对应 defaults-truncate-with-way-back。文件名和路径在中间截断,因为它们中间部分的差异更重要。数字、金额和日期绝不截断。

布局能够适应真实数据

使用最长的合理值测试每个字段。文本列设置 min-width: 0,头像等固定尺寸的容器设置 flex-shrink: 0,电子邮件地址和 URL 设置 overflow-wrap: anywhere。长电子邮件地址将行菜单挤出屏幕的情况对应 defaults-survives-long-content。

缺少可选字段时,应移除该行,而不是显示占位符。角色位置只显示一个短横线的情况对应 defaults-omit-empty-fields。

数字、日期和复数形式遵循区域设置

通过 Intl.NumberFormat、Intl.DateTimeFormat 和 Intl.PluralRules 格式化。显示 1 members 或原始值 1284 的情况对应 defaults-locale-format。

更新会主动播报

Toast、结果计数和行内验证信息应放在礼貌型实时区域 role="status" 中,该区域在文本变化前应为空。屏幕阅读器无法听到 Toast 的情况对应 defaults-announce-updates。

等待时立即显示反馈

操作应在 400ms 内响应,否则应立即显示反馈,例如乐观更新的值、骨架屏或进度条。加载分支返回 null 的情况对应 defaults-instant-feedback。

将微调图标或骨架屏延迟 150–300ms 显示,显示后至少保持 300–500ms。骨架屏闪现一帧的情况对应 defaults-no-flicker-loading。骨架屏应与其替代的布局相匹配。参见 recipes.md。

声音用于确认,绝不单独使用

声音适用于付款、上传或提交等确认场景,也适用于不容错过的错误提示。每个声音提示都应有对应的可见反馈,例如状态变化。成功提示音响起但屏幕上没有任何变化的情况对应 defaults-sound-has-a-twin。

输入、悬停、滚动和键盘导航不应发出声音。每次按键都发出点击声的情况对应 defaults-no-sound-on-repeat。

用户可以关闭声音,且音量初始值为 0.3。硬编码 audio.volume = 1 且没有关闭开关的情况对应 defaults-sound-optional。播放和合成点击声的示例见 recipes.md。

一次只打开一个对话框

绝不要在一个对话框上方再打开另一个对话框。改用菜单、弹出框或新页面。这对应 defaults-no-stacked-dialogs。

两者

每项检查都是一对。出错的行旁边就是替换它的行。

规则错误做法替代方案
defaults-fade-not-cut使用 overflow: auto,内容却被硬生生截断两端使用 mask-image 渐隐
defaults-no-clipped-shadow卡片阴影被 overflow: hidden 截断在滚动容器上设置 padding: 8px
defaults-scroll-not-wrap代码行换成两行显示使用 white-space: nowrap 和 overflow-x: auto
defaults-contain-overscroll抽屉列表滚动到底部时,页面也跟着滚动在抽屉上设置 overscroll-behavior: contain
defaults-sticky-border粘性页眉没有边缘分隔线border-bottom: 1px solid var(--gray-a4)
defaults-clear-sticky-chrome聚焦的字段被 56px 高的粘性页眉遮挡scroll-padding-block-start: 56px
defaults-ring-not-border弹出层同时使用 border: 1px solid #e5e5e5 和 box-shadow先在阴影中使用 0 0 0 1px var(--gray-a4),边框设为透明
defaults-layered-shadowsbox-shadow: 0 4px 16px rgba(0, 0, 0, 0.2)使用三个向下的阴影层,逐层增大模糊、降低不透明度
defaults-fade-the-shadowtransition: box-shadow 200ms在承载凸起阴影的 ::after 上设置 opacity
defaults-image-outline白色卡片上的照片没有边缘设置 outline: 1px solid rgba(0, 0, 0, 0.1),并设 outline-offset: -1px
defaults-no-nested-cards卡片内放着标题和另一张卡片标题放在一张卡片上方
defaults-rounded-not-pill按钮使用 border-radius: 9999pxborder-radius: var(--radius-2)
defaults-no-decoration卡片后方有渐变光晕使用纯色背景
defaults-color-scheme深色主题却使用浅色滚动条在根元素上设置 color-scheme: dark
defaults-quiet-theme-switch切换主题时所有颜色过渡同时触发关闭过渡一个帧
defaults-focus-keyboard-only.button:focus { box-shadow: 0 0 0 2px var(--accent) }.button:focus-visible { outline: 2px solid var(--accent) }
defaults-trap-and-return-focus按 Tab 键会聚焦到对话框后面的页面将焦点限制在对话框内,然后返回触发元素
defaults-hit-area16px 图标按钮的点击区域也是 16px在其 ::before 上设置 inset: -12px,形成 40px 的点击区域
defaults-name-icon-buttons<button><TrashIcon /></button><button aria-label="Delete">
defaults-not-color-alone仅用红点表示错误红点搭配图标或单词 Failed
defaults-links-are-links<div onClick={() => router.push("/settings")}><a href="/settings">
defaults-state-in-url筛选条件仅存储在 useState 中在 URL 中使用 ?status=open
defaults-allow-zoommaximum-scale=1, user-scalable=nowidth=device-width, initial-scale=1
defaults-no-tap-highlight每次点按时浏览器都会闪现灰色高亮设置 -webkit-tap-highlight-color: transparent,并添加 :active 样式
defaults-fast-tap按钮在点按 300ms 后才响应touch-action: manipulation
defaults-hover-capable-only.card:hover { transform: translateY(-2px) }将相同规则放在 @media (hover: hover) and (pointer: fine) 内
defaults-dynamic-viewport在应用外壳上设置 height: 100vhheight: 100dvh
defaults-safe-areas标签栏被主屏幕指示条遮挡配合 viewport-fit=cover 设置 padding-bottom: env(safe-area-inset-bottom)
defaults-controls-not-selectable长按会选中标签的文字在标签上设置 user-select: none
defaults-keys-ignore-inputs在搜索框中输入时,按 J 会移动选中项快捷键忽略 input、textarea 和 [contenteditable]
defaults-enter-submits搜索字段外没有包裹 form使用 form,并在其 onSubmit 中执行搜索
defaults-accept-messy-input电话号码字段拒绝 +1 (555) 010-2030接受输入,存储为 +15550102030,并以格式化后的形式显示
defaults-input-types邮箱输入使用 <input type="text">type="email" autocomplete="email"
defaults-input-16px移动端输入框使用 font-size: 14pxfont-size: 16px
defaults-label-hit-area复选框旁边是独立的 span将复选框和文字一起放在一个 label 中
defaults-validate-on-submit提交按钮使用 disabled={!isValid}保持启用,提交时显示错误并聚焦第一个错误
defaults-loading-button将按钮标签替换为加载动画保留标签,在旁边显示加载动画,并禁用按钮
defaults-undo-destructive删除操作立即执行,且无法撤销显示带有 Undo 的提示条
defaults-tabular-numbers计时器数字变化时宽度也跟着变化font-variant-numeric: tabular-nums
defaults-balanced-wrap标题最后一行只有一个单词h1 { text-wrap: balance } 和 p { text-wrap: pretty }
defaults-antialiased-root浅色文字使用默认的子像素平滑在根元素上设置 -webkit-font-smoothing: antialiased
defaults-inline-mono<code> 与所在句子的字号相同font-size: 0.9em
defaults-truncate-with-way-back文件名被截断,且没有其他查看方式使用工具提示显示完整名称
defaults-survives-long-content长邮箱地址把行菜单挤出屏幕在文本上设置 min-width: 0,在菜单上设置 flex-shrink: 0
defaults-omit-empty-fields缺少角色时显示破折号省略角色所在行
defaults-locale-format{count} members 在 count 为 1 时仍显示复数使用 Intl.PluralRules 选择 member 或 members
defaults-announce-updates提示条挂载时带有文字,却没有 role创建一个空的 role="status" 区域,并在其中更新文字
defaults-instant-feedbackif (isLoading) return nullif (isLoading) return <Skeleton />
defaults-no-flicker-loading对于 40ms 就返回的请求也显示加载动画200ms 后才显示,并至少保持 400ms
defaults-sound-has-a-twin执行 playSound("success"),却没有状态变化在播放声音的同时执行 setStatus("success")
defaults-no-sound-on-repeat在 onChange 中调用 playSound("keystroke")输入时不播放声音
defaults-sound-optionalaudio.volume = 1,且没有关闭开关提供声音设置,默认音量为 0.3
defaults-no-stacked-dialogs从设置对话框中打开确认对话框在对话框内使用菜单或弹出层

报告

严重程度。 HIGH 会影响使用或访问。例如,阴影被裁切、滚动被硬性截断、打字时触发快捷键、对话框层叠、目标尺寸小于 24px 或静默等待。还包括拒绝粘贴格式的字段、没有视觉对应项或关闭开关的声音。还包括没有名称的图标按钮、仅用颜色表示的状态、焦点逃出对话框、缩放被阻止或没有链接的路由。还包括必须先填写有效内容才能提交的表单、被截断且无法还原的值,或没有撤销或确认步骤的破坏性操作。还包括因值过长而被推到屏幕外的内容、隐藏控件的 100vh 外壳,或位于主页指示条下方的栏。

MEDIUM 包括胶囊按钮、点击时出现的焦点环,或在触屏上卡住的悬停效果。还包括数据中的比例数字、频繁操作时播放的声音、从覆盖层泄漏的滚动、刷新后丢失的状态,或闪烁的骨架屏。还包括使用错误键盘的字段、小于 16px 的移动端输入框、失效的标签、按 Enter 无法提交,或没有指示器的忙碌按钮。还包括未播报的更新、被固定界面元素遮挡的字段,或卡片中嵌套卡片。还包括点击闪光或点击延迟、可选择的控件标签,或未格式化的数字或复数形式。

LOW 包括阴影旁边不明显的边框、装饰性光晕、单个刺眼的阴影,或经过过渡动画的 box-shadow。还包括不平衡的标题、缺少轮廓的图像、没有边框的固定页眉、深色页面上的浅色滚动条、模糊的主题切换开关,或缺少根级字体平滑设置。还包括全尺寸的行内代码,或用于表示空字段的占位短横线。

格式。 每个根本原因列出一条发现:

file:line - [rule-id] what is wrong

然后提供 Rule | Count | Severity 汇总。仍有任何 HIGH 时使用 Block,否则使用 Approve。切勿对未阅读的文件使用 Approve。如果检查依赖布局,请打开屏幕;将所有无法运行的检查标记为 Not verified。

评论

支持 Markdown