web-ui-best-practices

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Web UI Best Practices

Web UI 最佳实践

When invoked generally, apply these opinionated constraints for building better interfaces and for any UI work in this conversation.
When invoked with a file specified (i.e.
web-ui-best-practices <file>
), review the file against all constraints below and output:
  1. violations (quote the exact line/snippet)
  2. why it matters (1 short sentence)
  3. a concrete fix (code-level suggestion)
在通用场景下,构建更优质界面或进行本次对话中的任何UI工作时,请遵循这些约束规则。
当指定文件调用时(例如
web-ui-best-practices <file>
),请对照以下所有约束规则评审该文件,并输出:
  1. 违规内容(引用确切的代码行/片段)
  2. 违规影响(一句话简要说明)
  3. 具体修复方案(代码层面的建议)

Stack

技术栈

  • MUST use Tailwind CSS defaults unless custom values already exist or are explicitly requested
  • MUST use
    motion/react
    (formerly
    framer-motion
    ) when JavaScript animation is required
  • SHOULD use
    tw-animate-css
    for entrance and micro-animations in Tailwind CSS
  • MUST use
    cn
    utility (
    clsx
    +
    tailwind-merge
    ) for class logic
  • 除非已存在自定义值或被明确要求,否则必须使用Tailwind CSS的默认配置
  • 当需要JavaScript动画时,必须使用
    motion/react
    (原
    framer-motion
  • 在Tailwind CSS中实现入场动画和微动画时,建议使用
    tw-animate-css
  • 处理类名逻辑时,必须使用
    cn
    工具(
    clsx
    +
    tailwind-merge

Components

组件

  • MUST use accessible component primitives for anything with keyboard or focus behavior (
    Base UI
    ,
    Radix
    ,
    React-Aria
    )
  • MUST use the project’s existing component primitives first
  • NEVER mix primitive systems within the same interaction surface
  • SHOULD prefer
    Base UI
    for new primitives if compatible with the stack
  • MUST add an
    aria-label
    to icon-only buttons
  • NEVER rebuild keyboard or focus behavior by hand unless explicitly requested
  • 对于任何涉及键盘或焦点行为的组件,必须使用可访问的组件基础库(
    Base UI
    Radix
    React-Aria
  • 必须优先使用项目中已有的组件基础库
  • 禁止在同一交互界面中混合使用不同的基础组件系统
  • 如果与技术栈兼容,新增基础组件时建议优先选择
    Base UI
  • 纯图标按钮必须添加
    aria-label
  • 除非被明确要求,否则禁止手动实现键盘或焦点行为

Interaction

交互

  • MUST use an
    AlertDialog
    for destructive or irreversible actions
  • SHOULD use structural skeletons for loading states
  • NEVER use
    h-screen
    , use
    h-dvh
  • MUST show errors next to where the action happens
  • NEVER block paste in
    input
    or
    textarea
    elements
  • 对于破坏性或不可逆操作,必须使用
    AlertDialog
  • 加载状态建议使用结构化骨架屏
  • 禁止使用
    h-screen
    ,请使用
    h-dvh
  • 错误提示必须显示在操作发生位置的附近
  • 禁止在
    input
    textarea
    元素中阻止粘贴操作

Navigation & State

导航与状态

  • SHOULD reflect UI state in the URL (filters, tabs, pagination, expanded panels via query params)
  • MUST use
    <a>
    /
    <Link>
    for navigation (Cmd/Ctrl+click and middle-click should work)
  • SHOULD deep-link stateful UI (if it uses
    useState
    , consider URL sync via
    nuqs
    or similar)
  • MUST require confirmation or undo window for destructive actions (never immediate)
  • 建议将UI状态同步到URL中(通过查询参数实现筛选、标签页、分页、展开面板等状态的同步)
  • 导航必须使用
    <a>
    /
    <Link>
    标签(支持Cmd/Ctrl+点击和中键点击打开新页面)
  • 建议为有状态的UI实现深度链接(如果使用了
    useState
    ,可考虑通过
    nuqs
    或类似工具实现与URL的同步)
  • 破坏性操作必须要求确认或提供撤销窗口,禁止直接执行

Touch & Interaction

触摸与交互

  • SHOULD set
    touch-action: manipulation
    on tappable controls (prevents double-tap zoom delay)
  • SHOULD set
    -webkit-tap-highlight-color
    intentionally
  • MUST use
    overscroll-behavior: contain
    in modals/drawers/sheets
  • SHOULD during drag: disable text selection,
    inert
    on dragged elements
  • SHOULD use
    autoFocus
    sparingly (desktop only, single primary input; avoid on mobile)
  • 可点击控件建议设置
    touch-action: manipulation
    (避免双击缩放延迟)
  • 建议显式设置
    -webkit-tap-highlight-color
  • 模态框/侧边栏/底部弹窗中必须使用
    overscroll-behavior: contain
  • 拖拽过程中建议:禁用文本选择,为拖拽元素设置
    inert
  • 建议谨慎使用
    autoFocus
    (仅在桌面端的单个主要输入框使用;避免在移动端使用)

Animation

动画

  • NEVER add animation unless it is explicitly requested
  • MUST animate only compositor props (
    transform
    ,
    opacity
    )
  • NEVER animate layout properties (
    width
    ,
    height
    ,
    top
    ,
    left
    ,
    margin
    ,
    padding
    )
  • SHOULD avoid animating paint properties (
    background
    ,
    color
    ) except for small, local UI (text, icons)
  • SHOULD use
    ease-out
    on entrance
  • NEVER exceed
    200ms
    for interaction feedback
  • MUST pause looping animations when off-screen
  • SHOULD respect
    prefers-reduced-motion
  • NEVER introduce custom easing curves unless explicitly requested
  • SHOULD avoid animating large images or full-screen surfaces
  • SHOULD never
    transition: all
    —list properties explicitly
  • SHOULD set correct
    transform-origin
  • SHOULD have animations be interruptible—respond to user input mid-animation
  • 除非被明确要求,否则禁止添加动画
  • 必须仅对合成器属性(
    transform
    opacity
    )执行动画
  • 禁止对布局属性(
    width
    height
    top
    left
    margin
    padding
    )执行动画
  • 建议避免对绘制属性(
    background
    color
    )执行动画,小型局部UI(文本、图标)除外
  • 入场动画建议使用
    ease-out
    缓动函数
  • 交互反馈动画时长不得超过
    200ms
  • 元素移出视口时,必须暂停循环动画
  • 建议遵循
    prefers-reduced-motion
    偏好设置
  • 除非被明确要求,否则禁止自定义缓动曲线
  • 建议避免对大型图片或全屏元素执行动画
  • 禁止使用
    transition: all
    ——需明确列出要过渡的属性
  • 建议设置正确的
    transform-origin
  • 动画必须支持中断——在动画过程中响应用户输入

Typography

排版

  • MUST use
    text-balance
    for headings and
    text-pretty
    for body/paragraphs
  • MUST use
    tabular-nums
    for data
  • SHOULD use
    truncate
    or
    line-clamp
    for dense UI
  • NEVER modify
    letter-spacing
    (
    tracking-*
    ) unless explicitly requested
  • SHOULD use
    not
    ...
  • SHOULD use curly quotes
    "
    "
    not straight
    "
  • SHOULD have non-breaking spaces:
    10&nbsp;MB
    ,
    ⌘&nbsp;K
    , brand names
  • SHOULD have loading states end with
    :
    "Loading…"
    ,
    "Saving…"
  • SHOULD use
    font-variant-numeric: tabular-nums
    for number columns/comparisons
  • SHOULD have flex children need
    min-w-0
    to allow text truncation
  • SHOULD handle empty states—don't render broken UI for empty strings/arrays
  • SHOULD consider that user-generated input fields may have short, average, and very long inputs
  • 标题必须使用
    text-balance
    ,正文/段落必须使用
    text-pretty
  • 数据类内容必须使用
    tabular-nums
  • 高密度UI中建议使用
    truncate
    line-clamp
    处理文本溢出
  • 除非被明确要求,否则禁止修改
    letter-spacing
    tracking-*
  • 建议使用
    而非
    ...
  • 建议使用弯引号
    而非直引号
    "
    "
  • 建议使用不换行空格:
    10&nbsp;MB
    ⌘&nbsp;K
    、品牌名称等
  • 加载状态文本建议以
    结尾:
    "加载中…"
    "保存中…"
  • 数字列/数字对比场景建议使用
    font-variant-numeric: tabular-nums
  • Flex子元素需要设置
    min-w-0
    以支持文本截断
  • 建议处理空状态——空字符串/数组场景下禁止渲染损坏的UI
  • 建议考虑用户生成的输入内容可能存在短文本、普通文本和超长文本的情况

Layout

布局

  • MUST use a fixed
    z-index
    scale (no arbitrary
    z-*
    )
  • SHOULD use
    size-*
    for square elements instead of
    w-*
    +
    h-*
  • 必须使用固定的
    z-index
    层级体系(禁止使用任意的
    z-*
    值)
  • 方形元素建议使用
    size-*
    而非同时设置
    w-*
    +
    h-*

Safe Areas & Layout

安全区域与布局

  • MUST respect
    env(safe-area-inset-*)
    for full-bleed layouts and fixed elements on notched devices
  • SHOULD avoid unwanted scrollbars (use
    overflow-x-hidden
    on containers and fix overflow at the source)
  • SHOULD prefer flex/grid over JS measurement for layout
  • 对于刘海屏设备的全屏布局和固定定位元素,必须遵循
    env(safe-area-inset-*)
    规则
  • 建议避免不必要的滚动条(在容器上使用
    overflow-x-hidden
    并从根源修复溢出问题)
  • 布局实现建议优先使用flex/grid而非JavaScript测量

Dark Mode & Theming

深色模式与主题

  • MUST set
    color-scheme: dark
    on
    <html>
    for dark themes (fixes scrollbars and native inputs)
  • SHOULD set
    <meta name="theme-color">
    to match the page background
  • SHOULD set explicit
    background-color
    and
    color
    on native
    <select>
    (Windows dark mode)
  • 深色主题下,必须在
    <html>
    标签上设置
    color-scheme: dark
    (修复滚动条和原生输入框的显示问题)
  • 建议设置
    <meta name="theme-color">
    以匹配页面背景色
  • 建议为原生
    <select>
    标签显式设置
    background-color
    color
    (适配Windows深色模式)

Locale & i18n

本地化与国际化

  • MUST use
    Intl.DateTimeFormat
    (no hardcoded date/time formats)
  • MUST use
    Intl.NumberFormat
    (no hardcoded number/currency formats)
  • SHOULD detect language via
    Accept-Language
    /
    navigator.languages
    , not IP
  • 必须使用
    Intl.DateTimeFormat
    (禁止硬编码日期/时间格式)
  • 必须使用
    Intl.NumberFormat
    (禁止硬编码数字/货币格式)
  • 建议通过
    Accept-Language
    /
    navigator.languages
    检测语言,而非通过IP地址

Hydration Safety

水化安全性

  • MUST provide
    onChange
    for inputs with
    value
    (or use
    defaultValue
    for uncontrolled inputs)
  • MUST guard date/time rendering against hydration mismatches (server vs client)
  • SHOULD use
    suppressHydrationWarning
    only where truly needed
  • value
    的输入框必须提供
    onChange
    (或对非受控输入框使用
    defaultValue
  • 必须避免日期/时间渲染时出现服务端与客户端的水化不匹配问题
  • 建议仅在真正必要的场景下使用
    suppressHydrationWarning

Hover & Interactive States

悬停与交互状态

  • SHOULD provide
    hover:
    states for buttons/links (visual feedback)
  • SHOULD increase contrast for interactive states (hover/active/focus more prominent than rest)
  • 按钮/链接建议设置
    hover:
    状态(提供视觉反馈)
  • 交互状态(悬停/激活/焦点)的对比度建议高于普通状态

Images

图片

  • MUST set explicit
    width
    and
    height
    on
    <img>
    (prevents CLS)
  • SHOULD set
    loading="lazy"
    for below-fold images
  • SHOULD set
    priority
    or
    fetchpriority="high"
    for above-fold critical images
  • <img>
    标签必须设置明确的
    width
    height
    (避免CLS布局偏移)
  • 屏幕外的图片建议设置
    loading="lazy"
  • 首屏关键图片建议设置
    priority
    fetchpriority="high"

Performance

性能

  • NEVER animate large
    blur()
    or
    backdrop-filter
    surfaces
  • NEVER apply
    will-change
    outside an active animation
  • NEVER use
    useEffect
    for anything that can be expressed as render logic
  • SHOULD virtualize large lists (>50 items) (e.g.
    virtua
    or
    content-visibility: auto
    where appropriate)
  • MUST avoid layout reads during render (
    getBoundingClientRect
    ,
    offsetHeight
    ,
    offsetWidth
    ,
    scrollTop
    )
  • SHOULD batch DOM reads/writes (avoid interleaving)
  • SHOULD prefer uncontrolled inputs; controlled inputs must be cheap per keystroke
  • SHOULD add
    <link rel="preconnect">
    for CDN/asset domains
  • SHOULD preload critical fonts (
    <link rel="preload" as="font">
    ) and use
    font-display: swap
  • 禁止对大面积元素执行
    blur()
    backdrop-filter
    动画
  • 禁止在非活跃动画场景下使用
    will-change
  • 任何可通过渲染逻辑实现的功能,禁止使用
    useEffect
  • 大型列表(超过50项)建议实现虚拟化(例如使用
    virtua
    或在合适场景下使用
    content-visibility: auto
  • 渲染过程中必须避免读取布局信息(
    getBoundingClientRect
    offsetHeight
    offsetWidth
    scrollTop
  • 建议批量处理DOM的读/写操作(避免交替执行)
  • 建议优先使用非受控输入框;受控输入框必须保证每次按键操作的性能开销极低
  • 建议为CDN/资源域名添加
    <link rel="preconnect">
  • 建议预加载关键字体(
    <link rel="preload" as="font">
    )并使用
    font-display: swap

Design

设计

  • NEVER use gradients unless explicitly requested
  • NEVER use purple or multicolor gradients
  • NEVER use glow effects as primary affordances
  • SHOULD use Tailwind CSS default shadow scale unless explicitly requested
  • MUST give empty states one clear next action
  • SHOULD limit accent color usage to one per view
  • SHOULD use existing theme or Tailwind CSS color tokens before introducing new ones
  • 除非被明确要求,否则禁止使用渐变
  • 禁止使用紫色或多色渐变
  • 禁止将发光效果作为主要交互提示
  • 除非被明确要求,否则建议使用Tailwind CSS的默认阴影层级
  • 空状态必须提供一个清晰的下一步操作
  • 单个视图中建议限制强调色的使用数量为一种
  • 引入新颜色前建议优先使用现有主题或Tailwind CSS的颜色变量

Design Direction (when aesthetics requested)

设计方向(当需要调整美学风格时)

  • MUST choose a clear aesthetic direction and execute consistently (e.g., brutally minimal, editorial, utilitarian, playful)
  • SHOULD use deliberate typography (1 display + 1 body) and avoid accidental defaults; follow product font system when it exists
  • SHOULD define theme/palette via CSS variables; use one dominant base + sharp accent
  • SHOULD match implementation complexity to the aesthetic (minimal = restraint; maximal = elaborate but controlled)
  • If motion is explicitly requested: prefer one cohesive high-impact sequence (load stagger, scroll reveal) over scattered micro-interactions
  • SHOULD avoid cookie-cutter layout/component patterns; make 1-2 distinctive choices grounded in context
  • 必须选择清晰的美学方向并保持执行一致性(例如:极简主义、编辑风格、实用主义、趣味风格)
  • 建议使用刻意设计的排版组合(1种标题字体 + 1种正文字体),避免随意使用默认字体;如果产品已有字体体系,请遵循该体系
  • 建议通过CSS变量定义主题/调色板;使用一种主导基础色 + 鲜明的强调色
  • 实现复杂度建议与美学风格匹配(极简风格=克制;繁复风格=精心设计但保持可控)
  • 如果明确要求添加动画:优先选择一个连贯的高影响力动画序列(加载 stagger 动画、滚动揭露动画)而非零散的微交互
  • 建议避免千篇一律的布局/组件模式;结合场景做出1-2个独特的设计选择

Content & Copy

内容与文案

  • SHOULD use active voice ("Install the CLI" not "The CLI will be installed")
  • SHOULD use specific button labels ("Save API Key" not "Continue")
  • SHOULD write error messages with a fix/next step, not just the problem
  • SHOULD write in second person; avoid first person
  • SHOULD use
    &
    over "and" where space-constrained
  • 建议使用主动语态(例如“安装CLI”而非“CLI将被安装”)
  • 按钮标签建议使用具体表述(例如“保存API密钥”而非“继续”)
  • 错误提示建议包含修复方案/下一步操作,而非仅说明问题
  • 建议使用第二人称表述;避免使用第一人称
  • 空间有限时建议使用
    &
    替代“和”

Anti-patterns (flag these)

反模式(需标记)

  • user-scalable=no
    or
    maximum-scale=1
    disabling zoom
  • onPaste
    with
    preventDefault
  • transition: all
  • outline-none
    without a
    focus-visible
    replacement
  • Inline
    onClick
    navigation without
    <a>
    /
    <Link>
  • <div>
    /
    <span>
    with click handlers (use
    <button>
    )
  • Images without dimensions
  • Large arrays
    .map()
    without virtualization
  • Form inputs without labels
  • Icon buttons without
    aria-label
  • Hardcoded date/number formats (use
    Intl.*
    )
  • autoFocus
    without clear justification
  • 使用
    user-scalable=no
    maximum-scale=1
    禁用缩放
  • onPaste
    事件中使用
    preventDefault
  • 使用
    transition: all
  • 使用
    outline-none
    但未提供
    focus-visible
    替代方案
  • 使用内联
    onClick
    实现导航而非
    <a>
    /
    <Link>
  • 使用
    <div>
    /
    <span>
    绑定点击事件(应使用
    <button>
  • 图片未设置尺寸
  • 大型数组使用
    .map()
    但未实现虚拟化
  • 表单输入框未设置标签
  • 纯图标按钮未添加
    aria-label
  • 硬编码日期/数字格式(应使用
    Intl.*
  • 无合理理由使用
    autoFocus

Rules if not found in primitives

基础库未覆盖场景下的规则

The below rules apply if the pattern is either explicitly requested or not found in the primitive itself already.
以下规则适用于场景被明确要求或基础库未覆盖的情况。

Accessibility

可访问性

  • Icon-only buttons need
    aria-label
  • Form controls need
    <label>
    or
    aria-label
  • Interactive elements need keyboard handlers (
    onKeyDown
    /
    onKeyUp
    )
  • <button>
    for actions,
    <a>
    /
    <Link>
    for navigation (not
    <div onClick>
    )
  • Images need
    alt
    (or
    alt=""
    if decorative)
  • Decorative icons need
    aria-hidden="true"
  • Async updates (toasts, validation) need
    aria-live="polite"
  • Use semantic HTML (
    <button>
    ,
    <a>
    ,
    <label>
    ,
    <table>
    ) before ARIA
  • Headings hierarchical
    <h1>
    <h6>
    ; include skip link for main content
  • scroll-margin-top
    on heading anchors
  • 纯图标按钮需要
    aria-label
  • 表单控件需要
    <label>
    aria-label
  • 交互元素需要键盘事件处理器(
    onKeyDown
    /
    onKeyUp
  • 动作使用
    <button>
    ,导航使用
    <a>
    /
    <Link>
    (禁止使用
    <div onClick>
  • 图片需要
    alt
    属性(装饰性图片使用
    alt=""
  • 装饰性图标需要设置
    aria-hidden="true"
  • 异步更新(提示框、验证信息)需要设置
    aria-live="polite"
  • 优先使用语义化HTML(
    <button>
    <a>
    <label>
    <table>
    )而非ARIA
  • 标题层级需遵循
    <h1>
    <h6>
    的结构;主内容区域需包含跳转链接
  • 标题锚点需要设置
    scroll-margin-top

Focus States

焦点状态

  • Interactive elements need visible focus:
    focus-visible:ring-*
    or equivalent
  • Never
    outline-none
    /
    outline: none
    without focus replacement
  • Use
    :focus-visible
    over
    :focus
    (avoid focus ring on click)
  • Group focus with
    :focus-within
    for compound controls
  • 交互元素需要可见的焦点样式:
    focus-visible:ring-*
    或同等替代方案
  • 禁止使用
    outline-none
    /
    outline: none
    但未提供焦点替代样式
  • 优先使用
    :focus-visible
    而非
    :focus
    (避免点击时显示焦点环)
  • 复合控件建议使用
    :focus-within
    实现组焦点

Forms

表单

  • Inputs need
    autocomplete
    and meaningful
    name
  • Use correct
    type
    (
    email
    ,
    tel
    ,
    url
    ,
    number
    ) and
    inputmode
  • Never block paste (
    onPaste
    +
    preventDefault
    )
  • Labels clickable (
    htmlFor
    or wrapping control)
  • Disable spellcheck on emails, codes, usernames (
    spellCheck={false}
    )
  • Checkboxes/radios: label + control share single hit target (no dead zones)
  • Submit button stays enabled until request starts; spinner during request
  • Errors inline next to fields; focus first error on submit
  • Placeholders end with
    and show example pattern
  • autocomplete="off"
    on non-auth fields to avoid password manager triggers
  • Warn before navigation with unsaved changes (
    beforeunload
    or router guard)
  • 输入框需要设置
    autocomplete
    和有意义的
    name
    属性
  • 使用正确的
    type
    email
    tel
    url
    number
    )和
    inputmode
  • 禁止阻止粘贴操作(
    onPaste
    +
    preventDefault
  • 标签需可点击(使用
    htmlFor
    属性或包裹控件)
  • 邮箱、验证码、用户名输入框需禁用拼写检查(
    spellCheck={false}
  • 复选框/单选框:标签与控件需共享同一个点击区域(无无效点击区域)
  • 提交按钮需保持可用直到请求开始;请求过程中显示加载指示器
  • 错误提示需显示在字段旁;提交时自动聚焦第一个错误字段
  • 占位符需以
    结尾并显示示例格式
  • 非认证字段设置
    autocomplete="off"
    以避免触发密码管理器
  • 存在未保存更改时,导航前需发出警告(使用
    beforeunload
    或路由守卫)",