mcpField
U
ui-engineering

ui-engineering

github.com/noobygains开发11559 次安装3 天前更新
代码仓库

关于 ui-engineering

ui-engineering 是指导前端组件实现的工程技能,面向构建 UI 的开发者。它强调先规划语义结构、状态、无障碍与响应式行为,并提供布局、状态管理、表单和性能方面的实践规则。

主要功能

  1. 01组件组合与架构检查
  2. 02Grid 与 Flexbox 选择指引
  3. 03状态归属原则
  4. 04响应式设计方法
  5. 05无障碍与表单规范
  6. 06动画及渲染性能建议

适用场景

  1. 01构建前端组件前规划结构与状态
  2. 02为页面选择布局方式
  3. 03实现响应式表单与导航
  4. 04检查交互组件的无障碍要求

安装

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

$npx skills add https://github.com/noobygains/godmode --skill ui-engineering

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

附带文件component-patterns.md

详细介绍

UI 工程

概述

以严谨的架构构建 UI 组件,而不是临时拼凑标记。

核心原则: 每项组件决策——布局策略、状态归属、无障碍设计、响应式行为——都遵循既定模式。UX Patterns 技能告诉你要构建什么。本技能告诉你如何以结构完整的方式构建。

前置条件: 先调用 godmode:ux-patterns,确定适用模式和令牌值。本技能假定令牌和模式已确立。

使用时机

以下情况必须使用:

  • 构建任何前端组件
  • 在 Grid 和 Flexbox 之间做选择
  • 决定状态应放在哪里
  • 设计响应式断点行为
  • 构建表单、数据可视化、导航或覆盖层
  • 引入动效或过渡效果

在以下步骤之后使用:

  • 设计令牌已确立(ux-patterns)
  • 目标 UI 模式已确定(ux-patterns)

首要指令

NO COMPONENT WITHOUT STRUCTURE, STATES, AND ACCESSIBILITY DEFINED FIRST

编写组件代码之前,先明确:语义结构(正确的 HTML 元素)、所有视觉状态(空、加载中、错误、已填充、禁用),以及无障碍要求(ARIA 属性、键盘交互、对比度)。

组件架构

组合优于配置

将组件组装成更小、可组合的单元,而不是构建臃肿且属性繁多的整体。

``` Dialog DialogHeader DialogTitle DialogDescription DialogBody DialogFooter ``` 每个单元都可独立使用,也可独立设置样式。 ``` Dialog (title, description, body, footer, headerAlign, footerAlign, showCloseButton, variant, size, overlayOpacity, titleSize, ...) ``` 属性泛滥、难以维护、无法扩展。
实现前检查清单

编写任何组件之前:

  1. 语义——哪个 HTML 元素才合适?(用 button 而不是 div onClick,用 nav 而不是 div className="nav")
  2. 属性——最精简的接口是什么?能否通过组合实现,而不是通过配置实现?
  3. 状态——默认、悬停、焦点、激活、禁用、加载中、错误、空
  4. 变体——需要哪些视觉变体?(主要、次要、幽灵、危险)
  5. 尺寸——有哪些尺寸等级?(sm、md、lg——最多 3-4 个)
  6. 响应式——在每个断点处如何变化?
  7. 无障碍——ARIA 角色、键盘导航路径、屏幕阅读器播报

布局策略选择

digraph layout_choice {
    rankdir=TB;
    q1 [label="What is being\narranged?", shape=diamond];
    q2 [label="Single axis or\ntwo axes?", shape=diamond];
    q3 [label="Are items\nuniform in size?", shape=diamond];

    grid [label="Use CSS Grid\ngrid-template-columns\ngrid-template-rows", shape=box];
    flex [label="Use Flexbox\nflex-direction\njustify/align", shape=box];
    grid_auto [label="Use CSS Grid\nauto-fill/auto-fit\nminmax()", shape=box];

    q1 -> q2;
    q2 -> grid [label="two axes\n(rows AND columns)"];
    q2 -> q3 [label="single axis\n(row OR column)"];
    q3 -> grid_auto [label="yes\n(uniform cards)"];
    q3 -> flex [label="no\n(nav items,\nform row)"];
}
适合使用 CSS Grid 的情况
  • 页面级框架(侧边栏 + 主内容 + 辅助栏)
  • 统一的卡片网格
  • 仪表板布局(指标卡片、图表区域)
  • 任何需要二维控制的布局
  • 跨行和跨列对齐

示例模式:

/* Self-adjusting card grid */
.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: var(--space-6);
}

/* Dashboard scaffold */
.dashboard {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  grid-template-rows: auto 1fr;
  gap: var(--space-6);
}
.dashboard .wide-chart { grid-column: span 2; }
适合使用 Flexbox 的情况
  • 单行导航项
  • 表单输入框与按钮的行内分组
  • 在容器内居中内容
  • 沿单轴分布宽度不一的元素

示例模式:

/* Navigation row */
.nav-row {
  display: flex;
  align-items: center;
  gap: var(--space-4);
}

/* Inline form group */
.inline-group {
  display: flex;
  align-items: flex-end;
  gap: var(--space-3);
}
.inline-group .input-field { flex: 1; }

状态归属策略

digraph state_ownership {
    rankdir=TB;
    q1 [label="Where does this\nstate belong?", shape=diamond];
    q2 [label="Consumed by\nmultiple components?", shape=diamond];
    q3 [label="Server-originated\nor client-only?", shape=diamond];
    q4 [label="Prop-drilling\nexceeds 3 levels?", shape=diamond];

    local [label="Component-local state\nuseState / ref", shape=box];
    server [label="Server state manager\nTanStack Query / SWR", shape=box];
    context [label="Context / Provider\nReact Context / provide-inject", shape=box];
    global [label="Global store\nZustand / Pinia / Signals", shape=box];

    q1 -> q2;
    q2 -> local [label="no\n(isolated component)"];
    q2 -> q3 [label="yes"];
    q3 -> server [label="server-originated\n(API responses,\ncached data)"];
    q3 -> q4 [label="client-only\n(UI flags,\npreferences)"];
    q4 -> context [label="no\n(2-3 levels)"];
    q4 -> global [label="yes\n(application-wide)"];
}

基本原则:

  1. 从局部状态开始。只有在有证据表明确有需要时才提升状态。
  2. 服务端数据不是客户端状态。应使用专用的服务端状态库管理。
  3. Context 用于依赖注入(主题、身份验证上下文),而不是用于高频更新。
  4. 全局存储是最后手段,而非起点。

响应式设计方法

移动优先的递进方式

先将移动端样式作为基线,再在更宽的断点逐步增加复杂性。

/* Mobile baseline */
.wrapper {
  padding: var(--space-4);
}

/* Tablet tier */
@media (min-width: 768px) {
  .wrapper {
    padding: var(--space-6);
    max-width: 768px;
    margin: 0 auto;
  }
}

/* Desktop tier */
@media (min-width: 1024px) {
  .wrapper {
    padding: var(--space-8);
    max-width: 1280px;
  }
}
响应式适配参考
元素移动端平板桌面端
导航汉堡菜单或底部抽屉标签栏或折叠侧边栏展开的侧边栏
卡片网格单列两列三至四列
数据表格卡片堆叠视图或水平滚动完整表格,减少列数完整表格
侧边栏 + 主内容区仅主内容区;侧边栏放入抽屉中仅显示图标的侧边栏完全展开的侧边栏
表单单列,输入框拉伸至全宽单列,最大宽度 560px成对字段使用两列
模态框全屏抽屉居中,占视口宽度的 80%居中,最大宽度 480px
主视觉区纵向排列(图片在标题下方)纵向排列,字体更大并排排列

无障碍标准

每个交互元素
  • 可通过 Tab 键访问
  • 焦点环清晰可见(:focus-visible,轮廓至少为 2px)
  • 可通过 Enter/Space(按钮)或 Enter(链接)激活
  • 具有无障碍名称(可见文本、aria-label 或 aria-labelledby)
  • 禁用状态会从 Tab 顺序中移除,或应用 aria-disabled
  • 移动端触控目标至少为 44x44px
表单
  • 每个输入框都有可见的 <label>(仅使用占位符不够)
  • 标明必填字段(星号加上 aria-required="true")
  • 错误消息与对应输入框关联(aria-describedby)
  • 错误提示不能仅依赖颜色(同时使用图标和文本)
  • 向屏幕阅读器播报提交结果(aria-live)
图片和图标
  • 有意义的图片带有描述性 alt 文本
  • 装饰性图片使用 alt="" 或 aria-hidden="true"
  • 仅含图标的按钮带有 aria-label
  • SVG 图标使用 role="img" 和 aria-label,或使用 aria-hidden="true"
颜色和对比度
  • 普通文本的对比度至少为 4.5:1(大号文本为 3:1:粗体 18px 及以上,或 24px 及以上)
  • 绝不只通过颜色传达信息(辅以图标、图案、文本)
  • 动画遵循 prefers-reduced-motion
  • 如果提供深色模式,配色方案需遵循 prefers-color-scheme

动画和动效

何时使用动画
  • 状态转换: 悬停、聚焦、展开/折叠、显示/隐藏
  • 反馈信号: 成功、错误、加载进度
  • 空间提示: 说明内容从何处出现或消失
何时不使用动画
  • 没有功能用途的装饰效果
  • UI 转换持续时间超过 300ms
  • 阻止用户交互的动效(强制等待)
  • 用户无法控制的持续运动
时长参考
交互时长缓动
悬停响应150msease
按钮按下100msease-out
模态框进入200msease-out
模态框退出150msease-in
抽屉滑入250msease-out
淡入200msease
页面转换200-300msease-in-out
尊重用户的动效偏好
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

表单架构

验证体验
  1. 不要在每次按键时都进行验证。 在失焦(离开字段)或提交表单时验证。
  2. 在字段下方内联显示错误,不要放在汇总横幅中。
  3. 错误文本替代辅助文本——不要同时显示两者。
  4. 错误提示使用颜色和图标——绝不能只依赖颜色(无障碍要求)。
  5. 保留有效字段指示器(复选标记或绿色边框),随着用户填写逐步显示。
  6. 提交期间禁用提交按钮,并显示加载指示器。
字段布局指南
  • 标签放在输入框上方(不要放在旁边,也不要仅使用占位符)
  • 使用 <fieldset> 和 <legend> 对相关字段分组
  • 必填字段用星号标记,并为屏幕阅读器添加 (required)
  • 可选字段可改为显示 “(optional)”
  • 表单最大宽度:单列 480-560px
  • 提交按钮左对齐,不要居中(模态框内除外)

渲染性能

关键路径优化
  1. 首屏内容优先加载。 延迟加载首屏下方的资源和脚本。
  2. 正文优先使用系统字体,除非品牌要求使用网页字体。网页字体会导致布局偏移。
  3. 规范使用图像: 设置 width/height 属性(防止 CLS),为首屏下方的图像设置 loading="lazy",并使用 srcset 实现响应式加载。
  4. 关注打包体积: 每个导入的库都会产生开销。添加依赖前,请先衡量其对打包体积的影响。
懒加载策略
  • 首屏下方的图像:loading="lazy"
  • 路由模块:动态导入/代码拆分
  • 大型组件(图表、富文本编辑器):在交互时或组件可见时加载
  • 切勿对首屏内容进行懒加载

常见错误

错误修正方法
所有内容都使用 div使用语义化 HTML(button、nav、main、section、article)
仅用占位符作为标签始终提供可见的 <label> 元素
到处使用像素字面值使用设计系统中的令牌变量
容器宽度固定使用最大宽度搭配百分比宽度或自动边距
移除焦点轮廓设置 :focus-visible 的样式,而不是移除轮廓
在 div 上添加点击处理程序交互元素使用 <button> 或 <a>
使用外边距控制布局间距使用 Grid 或 Flexbox 的 gap
导入整个图标库单独导入图标;启用 tree-shaking
只实现顺利流程在实现顺利流程前,先设计好所有状态
只在桌面设备上测试先测试移动设备,再验证桌面设备

集成

前置条件:

  • godmode:ux-patterns —— 必须先建立令牌和模式

互补技能:

  • godmode:design-integration —— 在现有设计系统中工作时使用
  • godmode:test-first —— 组件测试遵循测试优先方法

支持文件:

  • component-patterns.md —— 内置无障碍支持的可复用组件蓝图

评论

支持 Markdown