AI 生成界面的无障碍:模型常漏的检查项AI 生成介面的無障礙:模型常漏的檢查項Accessibility in AI-generated UI: the checks models skipAI生成UIのアクセシビリティ:モデルが飛ばすチェックAI 생성 UI의 접근성: 모델이 빠뜨리는 점검Kebolehcapaian dalam UI jana AI: semakan yang dilangkau modelKhả năng tiếp cận trong UI do AI tạo: những kiểm tra mô hình bỏ quaAccessibilité de l'UI générée par IA : les vérifications oubliéesAccesibilidad en UI generada por IA: las comprobaciones que se saltanBarrierefreiheit in KI-generierter UI: die übersprungenen Checks
生成的界面看着没问题,键盘和读屏却用不了。先用无障碍底层组件,再按 WCAG 2.2 走查。生成的介面看著沒問題,鍵盤和讀屏卻用不了。先用無障礙底層元件,再按 WCAG 2.2 檢查。Generated UIs look fine and fail keyboards and screen readers. Start from accessible primitives, then audit against WCAG 2.2.見た目は良くてもキーボードやスクリーンリーダーで失敗。アクセシブルな基盤からWCAG 2.2で監査。보기엔 괜찮아도 키보드·스크린리더에서 실패. 접근성 기반에서 시작해 WCAG 2.2로 점검.Nampak baik tetapi gagal untuk papan kekunci dan pembaca skrin. Mula dengan primitif boleh capai, audit dengan WCAG 2.2.Trông ổn nhưng hỏng với bàn phím và trình đọc màn hình. Dùng primitive dễ tiếp cận, kiểm theo WCAG 2.2.Belles mais inutilisables au clavier. Partir de primitives accessibles, auditer selon WCAG 2.2.Se ven bien pero fallan con teclado y lector. Parte de primitivas accesibles y audita con WCAG 2.2.Sieht gut aus, scheitert an Tastatur und Screenreader. Mit barrierefreien Primitives starten, nach WCAG 2.2 prüfen.

正文以簡體中文顯示。
本文は英語で表示しています。
본문은 영어로 표시됩니다.
Kandungan dipaparkan dalam bahasa Inggeris.
Nội dung hiển thị bằng tiếng Anh.
Le corps de l’article est en anglais.
El cuerpo del artículo está en inglés.
Der Beitragstext ist auf Englisch.
Models optimise for what a screenshot shows. Focus order, accessible names, keyboard behaviour and live regions do not show up in screenshots, so they are the first things to go missing from generated UI. The good news is that the failures are predictable. This post lists the checks models skip most often, gives the fix for each, and shows how to make accessibility part of the agent's definition of done instead of a final pass nobody has time for.

Why generated UI fails in the same places
A generator learns from millions of pages, and a large share of the web has accessibility problems. Automated audits of popular home pages keep finding the same short list: low-contrast text, missing alternative text, empty links and buttons, missing form labels. Those are exactly the patterns a model reproduces when nobody asks for anything else. The fix is not a smarter model; it is explicit constraints plus a check the agent runs itself.
The checks models skip most
1. Clickable divs. <div onClick> looks like a button and is not one: no focus, no Enter or Space, no role. Use <button> for actions and <a href> for navigation.
<!-- generated -->
<div class="btn" onclick="save()">Save</div>
<!-- fixed -->
<button type="button" class="btn" onclick="save()">Save</button>

2. Missing focus styles. Generators often add outline: none to remove the browser ring because it "looks messy" in screenshots. Replace it, don't remove it:
:focus { outline: none; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
:focus-visible shows the ring for keyboard users and hides it for most mouse clicks, which is what designers usually wanted in the first place.
3. Icon-only buttons with no name. A trash icon is obvious to sighted users and silent to a screen reader. Add aria-label="Delete project" or visually hidden text.
4. Contrast of secondary text. Grey-on-grey captions, placeholders and disabled labels are the most common WCAG failure (success criterion 1.4.3 asks for 4.5:1 for normal text). Check both themes.
5. Target size. WCAG 2.2 adds 2.5.8 Target Size (Minimum): interactive targets should be at least 24×24 CSS pixels, or have enough spacing. Tiny close buttons and dense icon toolbars fail it on phones.
6. Dialogs without focus management. A modal must move focus inside when it opens, keep Tab inside while open, close on Escape and return focus to the trigger. The ARIA Authoring Practices Guide documents the pattern; Radix, React Aria and the native <dialog> element implement it.
7. Forms without labels. Placeholder text is not a label; it disappears when you type. Every input needs a <label for> or aria-labelledby, and errors should be linked with aria-describedby.
8. Dynamic updates nobody announces. "Saved", "3 results" and validation errors that appear without a page change need a live region (role="status" or aria-live="polite") to be heard.
Step by step: build accessibility into the workflow
Step 1: generate on accessible primitives. Ask the agent to use your kit built on Radix, React Aria or native elements. It is much easier to keep accessibility than to retrofit it.
Step 2: put the rules in the prompt and in AGENTS.md. A short list beats a long one: semantic elements, visible focus, labels, 4.5:1 contrast, 24px targets, dialog focus management.
Step 3: run an automated check. axe-core catches a meaningful share of issues automatically. With Playwright you can make it part of the test suite:
import { test, expect } from "@playwright/test";
import AxeBuilder from "@axe-core/playwright";
test("pricing page has no detectable a11y violations", async ({ page }) => {
await page.goto("/pricing");
const results = await new AxeBuilder({ page })
.withTags(["wcag2a", "wcag2aa", "wcag22aa"])
.analyze();
expect(results.violations).toEqual([]);
});
Step 4: do a two-minute keyboard pass. Unplug the mouse. Tab through the page: can you see where you are, reach everything, open and close every menu, and never get trapped? Automated tools cannot judge focus order or whether a label makes sense.
Step 5: listen once. Turn on VoiceOver or NVDA and read the main flow. Five minutes is enough to find unlabeled buttons and confusing headings.
What to put in the pull-request template
A short, repeated checklist does more than a long policy document nobody opens. Ours has five lines: keyboard pass done (yes/no), new interactive elements are native or use an accessible primitive, contrast checked in both themes, new images have alt text or are marked decorative, and axe test passes. When an agent opens the pull request, ask it to fill in the template honestly and to write NEEDS HUMAN where it could not check something itself, such as how the flow sounds in a screen reader.
Pitfalls
- Treating automated scores as done. Automated tools find only part of the problems; keyboard and screen-reader checks find the rest.
- ARIA as decoration.
role="button"on a div still needs keyboard handling. The first rule of ARIA is to prefer native elements. - Hiding focus for aesthetics. Use
:focus-visibleinstead. - Motion without an off switch. Respect
prefers-reduced-motion. - Colour as the only signal. Red borders for errors need text too.
Questions we get
Which WCAG level should we aim for? WCAG 2.2 AA is the common target and what most accessibility laws and procurement rules refer to. Start there; individual AAA criteria are worth adopting where they are cheap, such as larger targets.
Can the agent test with a screen reader itself? Not reliably. It can run axe, check the accessibility tree and reason about labels, but a short human pass with VoiceOver or NVDA still finds problems no tool reports, such as confusing reading order or redundant announcements.
Does using Radix or React Aria make us compliant? It makes compliance much easier for the widgets they cover. You still own contrast, labels, headings, alt text, focus styles and the content itself.
How do we stop regressions? Keep the axe test in CI, add a keyboard-only end-to-end test for the main flow, and include accessibility items in the pull-request template so reviewers check them every time.
Our take
Make accessibility structural, not a final pass. Generate on top of accessible primitives, keep the eight checks above in your prompts, run axe in CI and add an audit skill (accessibility, web-design-guidelines) to the agent's definition of done. Accessible UI is also better UI for everyone: keyboard power users, people on bright-sunlit phones, and the agent itself, which navigates pages through the same accessibility tree screen readers use.

Checklist
- Actions are
<button>, navigation is<a href> - Visible
:focus-visiblestyle on every interactive element - Icon-only controls have accessible names
- Text contrast ≥ 4.5:1 in both themes
- Targets ≥ 24×24 CSS px on mobile
- Dialogs trap focus, close on Escape, return focus
- Inputs have labels; errors linked with aria-describedby
- axe check in CI plus a manual keyboard pass
模型优化的是截图里看得到的东西。焦点顺序、可访问名称、键盘操作和实时播报区域在截图里都看不到,所以它们总是生成界面里最先缺失的部分。好消息是,这些问题非常可预测。这篇列出模型最常漏掉的检查项、每一项的修法,以及怎么把无障碍变成 Agent "完成标准"的一部分,而不是一个永远没时间做的收尾环节。

为什么生成界面总在同样的地方出错
生成器从海量网页中学习,而网上相当大比例的页面本身就有无障碍问题。对热门网站首页的自动化审查,反复发现的总是那几项:文字对比度低、图片缺替代文本、空链接和空按钮、表单缺标签。没人提额外要求时,模型复现的正是这些模式。解决办法不是更聪明的模型,而是明确的约束,加上一个 Agent 自己会跑的检查。
模型最常漏掉的检查项
1. 可点击的 div。 <div onClick> 看起来像按钮,但不是按钮:没有焦点、不响应 Enter 和空格、没有角色。操作用 <button>,跳转用 <a href>。
<!-- 生成的 -->
<div class="btn" onclick="save()">保存</div>
<!-- 修正后 -->
<button type="button" class="btn" onclick="save()">保存</button>

2. 没有焦点样式。 生成器经常加 outline: none 去掉浏览器的焦点框,因为它在截图里"看着乱"。要替换,而不是删除:
:focus { outline: none; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
:focus-visible 会对键盘用户显示焦点框,对大多数鼠标点击隐藏,这通常正是设计师最初想要的效果。
3. 只有图标、没有名称的按钮。 垃圾桶图标对明眼用户很直观,对读屏器却是一片沉默。加上 aria-label="删除项目" 或视觉隐藏的文字。
4. 次要文字对比度。 灰底灰字的说明、占位文字、禁用标签,是最常见的 WCAG 不合格项(成功准则 1.4.3 要求普通文字 4.5:1)。两套主题都要查。
5. 点击区域大小。 WCAG 2.2 新增了 2.5.8"目标尺寸(最低)":可交互目标至少 24×24 CSS 像素,或者周围留够间距。小小的关闭按钮和密集的图标工具栏在手机上都过不了。
6. 对话框没有焦点管理。 弹窗打开时焦点要移进去,打开期间 Tab 不能跑出去,按 Escape 能关闭,关闭后焦点回到触发按钮。ARIA Authoring Practices Guide 写清了这个模式;Radix、React Aria 和原生 <dialog> 元素都实现了它。
7. 表单没有标签。 占位文字不是标签,一输入就消失了。每个输入框都需要 <label for> 或 aria-labelledby,错误信息用 aria-describedby 关联。
8. 动态更新没人播报。"已保存""找到 3 条结果"和校验错误,如果出现时页面没有跳转,就需要实时区域(role="status" 或 aria-live="polite")才能被听到。
分步把无障碍嵌进工作流
第 1 步:在可访问的原语上生成。 让 Agent 使用基于 Radix、React Aria 或原生元素的组件。保持无障碍比事后补救容易得多。
第 2 步:把规则写进提示词和 AGENTS.md。 短清单比长清单好用:语义元素、可见焦点、标签、4.5:1 对比度、24px 点击区域、对话框焦点管理。
第 3 步:跑自动化检查。 axe-core 能自动发现相当一部分问题。配合 Playwright,可以把它变成测试的一部分:
import { test, expect } from "@playwright/test";
import AxeBuilder from "@axe-core/playwright";
test("定价页没有可检测到的无障碍问题", async ({ page }) => {
await page.goto("/pricing");
const results = await new AxeBuilder({ page })
.withTags(["wcag2a", "wcag2aa", "wcag22aa"])
.analyze();
expect(results.violations).toEqual([]);
});
第 4 步:两分钟键盘测试。 拔掉鼠标,用 Tab 走一遍页面:能不能看清当前位置、能不能到达所有元素、能不能打开和关闭每个菜单、会不会被困住?自动化工具判断不了焦点顺序,也判断不了标签写得是否合理。
第 5 步:听一遍。 打开 VoiceOver 或 NVDA,把主流程读一遍。五分钟就足以发现没有名称的按钮和令人困惑的标题。
PR 模板里写什么
一份简短、每次都会看到的清单,比一份没人打开的长篇规范更有用。我们的模板只有五行:做过键盘测试(是/否)、新增的可交互元素是原生元素或基于可访问原语、两套主题都查过对比度、新图片有替代文本或已标记为装饰、axe 测试通过。由 Agent 提交 PR 时,要求它如实填写模板,对于自己无法检查的项(比如这个流程在读屏器里听起来怎样),写上「需人工」。
常见坑
- 把自动化分数当成完成。 自动化工具只能发现一部分问题,其余要靠键盘和读屏测试。
- 把 ARIA 当装饰。 给 div 加
role="button"仍然需要自己处理键盘。ARIA 第一原则是优先用原生元素。 - 为了好看隐藏焦点。 改用
:focus-visible。 - 动效没有关闭途径。 遵守
prefers-reduced-motion。 - 只用颜色传达信息。 错误状态的红框还需要配文字。
常见问题
应该达到 WCAG 哪个等级? 通常以 WCAG 2.2 AA 为目标,大多数无障碍法规和采购要求引用的也是它。先做到 AA;个别 AAA 条款在成本很低时值得采用,比如更大的点击区域。
Agent 能自己用读屏器测试吗? 不太可靠。它可以跑 axe、检查无障碍树、推理标签是否合理,但人用 VoiceOver 或 NVDA 简单过一遍,仍能发现工具报告不了的问题,比如混乱的朗读顺序或重复播报。
用了 Radix 或 React Aria 就合规了吗? 对它们覆盖的控件来说,合规会容易很多。但对比度、标签、标题、替代文本、焦点样式和内容本身,仍然是你的责任。
怎么防止退步? 在 CI 里保留 axe 测试,为主流程加一个只用键盘的端到端测试,并在 PR 模板里加入无障碍检查项,让评审者每次都过一遍。
我们的看法
让无障碍成为结构,而不是收尾。在可访问的原语上生成,把上面八项检查写进提示词,在 CI 里跑 axe,再把走查 skill(accessibility、web-design-guidelines)加进 Agent 的完成标准。无障碍的界面对所有人都更好:键盘重度用户、在阳光下看手机的人,还有 Agent 自己,它浏览网页时用的正是读屏器使用的那棵无障碍树。

清单
- 操作用
<button>,跳转用<a href> - 每个可交互元素都有可见的
:focus-visible样式 - 纯图标控件有可访问名称
- 两套主题下文字对比度 ≥ 4.5:1
- 手机上点击区域 ≥ 24×24 CSS 像素
- 对话框锁定焦点、Escape 关闭、焦点回归
- 输入框有标签,错误用 aria-describedby 关联
- CI 里跑 axe,并做一次手动键盘测试
Models optimise for what a screenshot shows. Focus order, accessible names, keyboard behaviour and live regions do not show up in screenshots, so they are the first things to go missing from generated UI. The good news is that the failures are predictable. This post lists the checks models skip most often, gives the fix for each, and shows how to make accessibility part of the agent's definition of done instead of a final pass nobody has time for.

Why generated UI fails in the same places
A generator learns from millions of pages, and a large share of the web has accessibility problems. Automated audits of popular home pages keep finding the same short list: low-contrast text, missing alternative text, empty links and buttons, missing form labels. Those are exactly the patterns a model reproduces when nobody asks for anything else. The fix is not a smarter model; it is explicit constraints plus a check the agent runs itself.
The checks models skip most
1. Clickable divs. <div onClick> looks like a button and is not one: no focus, no Enter or Space, no role. Use <button> for actions and <a href> for navigation.
<!-- generated -->
<div class="btn" onclick="save()">Save</div>
<!-- fixed -->
<button type="button" class="btn" onclick="save()">Save</button>

2. Missing focus styles. Generators often add outline: none to remove the browser ring because it "looks messy" in screenshots. Replace it, don't remove it:
:focus { outline: none; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
:focus-visible shows the ring for keyboard users and hides it for most mouse clicks, which is what designers usually wanted in the first place.
3. Icon-only buttons with no name. A trash icon is obvious to sighted users and silent to a screen reader. Add aria-label="Delete project" or visually hidden text.
4. Contrast of secondary text. Grey-on-grey captions, placeholders and disabled labels are the most common WCAG failure (success criterion 1.4.3 asks for 4.5:1 for normal text). Check both themes.
5. Target size. WCAG 2.2 adds 2.5.8 Target Size (Minimum): interactive targets should be at least 24×24 CSS pixels, or have enough spacing. Tiny close buttons and dense icon toolbars fail it on phones.
6. Dialogs without focus management. A modal must move focus inside when it opens, keep Tab inside while open, close on Escape and return focus to the trigger. The ARIA Authoring Practices Guide documents the pattern; Radix, React Aria and the native <dialog> element implement it.
7. Forms without labels. Placeholder text is not a label; it disappears when you type. Every input needs a <label for> or aria-labelledby, and errors should be linked with aria-describedby.
8. Dynamic updates nobody announces. "Saved", "3 results" and validation errors that appear without a page change need a live region (role="status" or aria-live="polite") to be heard.
Step by step: build accessibility into the workflow
Step 1: generate on accessible primitives. Ask the agent to use your kit built on Radix, React Aria or native elements. It is much easier to keep accessibility than to retrofit it.
Step 2: put the rules in the prompt and in AGENTS.md. A short list beats a long one: semantic elements, visible focus, labels, 4.5:1 contrast, 24px targets, dialog focus management.
Step 3: run an automated check. axe-core catches a meaningful share of issues automatically. With Playwright you can make it part of the test suite:
import { test, expect } from "@playwright/test";
import AxeBuilder from "@axe-core/playwright";
test("pricing page has no detectable a11y violations", async ({ page }) => {
await page.goto("/pricing");
const results = await new AxeBuilder({ page })
.withTags(["wcag2a", "wcag2aa", "wcag22aa"])
.analyze();
expect(results.violations).toEqual([]);
});
Step 4: do a two-minute keyboard pass. Unplug the mouse. Tab through the page: can you see where you are, reach everything, open and close every menu, and never get trapped? Automated tools cannot judge focus order or whether a label makes sense.
Step 5: listen once. Turn on VoiceOver or NVDA and read the main flow. Five minutes is enough to find unlabeled buttons and confusing headings.
What to put in the pull-request template
A short, repeated checklist does more than a long policy document nobody opens. Ours has five lines: keyboard pass done (yes/no), new interactive elements are native or use an accessible primitive, contrast checked in both themes, new images have alt text or are marked decorative, and axe test passes. When an agent opens the pull request, ask it to fill in the template honestly and to write NEEDS HUMAN where it could not check something itself, such as how the flow sounds in a screen reader.
Pitfalls
- Treating automated scores as done. Automated tools find only part of the problems; keyboard and screen-reader checks find the rest.
- ARIA as decoration.
role="button"on a div still needs keyboard handling. The first rule of ARIA is to prefer native elements. - Hiding focus for aesthetics. Use
:focus-visibleinstead. - Motion without an off switch. Respect
prefers-reduced-motion. - Colour as the only signal. Red borders for errors need text too.
Questions we get
Which WCAG level should we aim for? WCAG 2.2 AA is the common target and what most accessibility laws and procurement rules refer to. Start there; individual AAA criteria are worth adopting where they are cheap, such as larger targets.
Can the agent test with a screen reader itself? Not reliably. It can run axe, check the accessibility tree and reason about labels, but a short human pass with VoiceOver or NVDA still finds problems no tool reports, such as confusing reading order or redundant announcements.
Does using Radix or React Aria make us compliant? It makes compliance much easier for the widgets they cover. You still own contrast, labels, headings, alt text, focus styles and the content itself.
How do we stop regressions? Keep the axe test in CI, add a keyboard-only end-to-end test for the main flow, and include accessibility items in the pull-request template so reviewers check them every time.
Our take
Make accessibility structural, not a final pass. Generate on top of accessible primitives, keep the eight checks above in your prompts, run axe in CI and add an audit skill (accessibility, web-design-guidelines) to the agent's definition of done. Accessible UI is also better UI for everyone: keyboard power users, people on bright-sunlit phones, and the agent itself, which navigates pages through the same accessibility tree screen readers use.

Checklist
- Actions are
<button>, navigation is<a href> - Visible
:focus-visiblestyle on every interactive element - Icon-only controls have accessible names
- Text contrast ≥ 4.5:1 in both themes
- Targets ≥ 24×24 CSS px on mobile
- Dialogs trap focus, close on Escape, return focus
- Inputs have labels; errors linked with aria-describedby
- axe check in CI plus a manual keyboard pass
AI 提示词AI 提示詞AI promptAIプロンプトAI 프롬프트Prompt AIPrompt cho AIPrompt IAPrompt de IAKI-Prompt
复制给 Claude、Cursor、v0 等 AI 助手,让它按本文的方法处理你的项目。尖括号里的内容换成你自己的。複製給 Claude、Cursor、v0 等 AI 助手,讓它按本文的方法處理你的專案。尖括號裡的內容換成你自己的。Paste this into Claude, Cursor, v0 or another assistant to apply this post to your own project. Replace the parts in angle brackets.Claude・Cursor・v0 などのAIアシスタントに貼り付けると、この記事の方法をあなたのプロジェクトに適用できます。山括弧の部分は自分の内容に置き換えてください。Claude, Cursor, v0 같은 AI 도우미에 붙여 넣으면 이 글의 방법을 내 프로젝트에 적용할 수 있습니다. 꺾쇠괄호 안은 내 내용으로 바꾸세요.Tampal ke Claude, Cursor, v0 atau pembantu lain untuk menggunakan kaedah artikel ini pada projek anda. Gantikan bahagian dalam kurungan sudut.Dán vào Claude, Cursor, v0 hoặc trợ lý khác để áp dụng bài này cho dự án của bạn. Thay phần trong dấu ngoặc nhọn bằng nội dung của bạn.Collez-le dans Claude, Cursor, v0 ou un autre assistant pour appliquer cet article à votre projet. Remplacez les parties entre chevrons.Pégalo en Claude, Cursor, v0 u otro asistente para aplicar este artículo a tu proyecto. Sustituye lo que está entre corchetes angulares.In Claude, Cursor, v0 oder einen anderen Assistenten einfügen, um diesen Beitrag auf dein Projekt anzuwenden. Teile in spitzen Klammern ersetzen.
对 <页面或组件> 做无障碍走查,并修复发现的问题。按顺序逐项检查,每项报告为"通过 / 已修复 / 需人工":
1. 操作用 <button>,跳转用 <a href>;没有可点击的 div/span。
2. 每个可交互元素都有可见的 :focus-visible 样式;没有单独的 outline:none。
3. 纯图标控件有可访问名称(aria-label 或视觉隐藏文字)。
4. 浅色和深色主题下文字对比度 ≥ 4.5:1(大字和界面组件 3:1);列出比值。
5. 触控目标 ≥ 24×24 CSS 像素,或者间距足够。
6. 对话框/菜单:打开时焦点移入,Tab 不跑出去,Escape 关闭,焦点回到触发按钮。
7. 每个输入框都有程序可识别的标签;错误用 aria-describedby 关联;不用占位文字代替标签。
8. 状态消息(已保存、结果数量、错误)使用 role="status" 或 aria-live。
9. 标题层级构成合理的大纲;图片有有意义的 alt,装饰图用 alt=""。
最后为这个页面加一个 @axe-core/playwright 测试(标签 wcag2a、wcag2aa、wcag22aa)。
优先使用原生元素而不是 ARIA。除修复所需外,不要改动视觉设计。对 <页面或组件> 做无障碍走查,并修复发现的问题。按顺序逐项检查,每项报告为"通过 / 已修复 / 需人工":
1. 操作用 <button>,跳转用 <a href>;没有可点击的 div/span。
2. 每个可交互元素都有可见的 :focus-visible 样式;没有单独的 outline:none。
3. 纯图标控件有可访问名称(aria-label 或视觉隐藏文字)。
4. 浅色和深色主题下文字对比度 ≥ 4.5:1(大字和界面组件 3:1);列出比值。
5. 触控目标 ≥ 24×24 CSS 像素,或者间距足够。
6. 对话框/菜单:打开时焦点移入,Tab 不跑出去,Escape 关闭,焦点回到触发按钮。
7. 每个输入框都有程序可识别的标签;错误用 aria-describedby 关联;不用占位文字代替标签。
8. 状态消息(已保存、结果数量、错误)使用 role="status" 或 aria-live。
9. 标题层级构成合理的大纲;图片有有意义的 alt,装饰图用 alt=""。
最后为这个页面加一个 @axe-core/playwright 测试(标签 wcag2a、wcag2aa、wcag22aa)。
优先使用原生元素而不是 ARIA。除修复所需外,不要改动视觉设计。Audit <page or component> for accessibility and fix what you find. Work through this list in order and report each item as PASS / FIXED / NEEDS HUMAN:
1. Actions use <button>, navigation uses <a href>; no clickable div/span.
2. Every interactive element has a visible :focus-visible style; no bare outline:none.
3. Icon-only controls have an accessible name (aria-label or visually hidden text).
4. Text contrast ≥ 4.5:1 (3:1 for large text and UI parts) in light AND dark themes; list the ratios.
5. Touch targets ≥ 24×24 CSS px or adequately spaced.
6. Dialogs/menus: focus moves in on open, Tab stays inside, Escape closes, focus returns to the trigger.
7. Every input has a programmatic label; errors linked with aria-describedby; no placeholder-as-label.
8. Status messages (saved, results count, errors) use role="status" or aria-live.
9. Headings form a logical outline; images have meaningful alt or alt="".
Then add an @axe-core/playwright test for this page (tags wcag2a, wcag2aa, wcag22aa).
Prefer native elements over ARIA. Do not change the visual design beyond what a fix requires.Audit <page or component> for accessibility and fix what you find. Work through this list in order and report each item as PASS / FIXED / NEEDS HUMAN:
1. Actions use <button>, navigation uses <a href>; no clickable div/span.
2. Every interactive element has a visible :focus-visible style; no bare outline:none.
3. Icon-only controls have an accessible name (aria-label or visually hidden text).
4. Text contrast ≥ 4.5:1 (3:1 for large text and UI parts) in light AND dark themes; list the ratios.
5. Touch targets ≥ 24×24 CSS px or adequately spaced.
6. Dialogs/menus: focus moves in on open, Tab stays inside, Escape closes, focus returns to the trigger.
7. Every input has a programmatic label; errors linked with aria-describedby; no placeholder-as-label.
8. Status messages (saved, results count, errors) use role="status" or aria-live.
9. Headings form a logical outline; images have meaningful alt or alt="".
Then add an @axe-core/playwright test for this page (tags wcag2a, wcag2aa, wcag22aa).
Prefer native elements over ARIA. Do not change the visual design beyond what a fix requires.Audit <page or component> for accessibility and fix what you find. Work through this list in order and report each item as PASS / FIXED / NEEDS HUMAN:
1. Actions use <button>, navigation uses <a href>; no clickable div/span.
2. Every interactive element has a visible :focus-visible style; no bare outline:none.
3. Icon-only controls have an accessible name (aria-label or visually hidden text).
4. Text contrast ≥ 4.5:1 (3:1 for large text and UI parts) in light AND dark themes; list the ratios.
5. Touch targets ≥ 24×24 CSS px or adequately spaced.
6. Dialogs/menus: focus moves in on open, Tab stays inside, Escape closes, focus returns to the trigger.
7. Every input has a programmatic label; errors linked with aria-describedby; no placeholder-as-label.
8. Status messages (saved, results count, errors) use role="status" or aria-live.
9. Headings form a logical outline; images have meaningful alt or alt="".
Then add an @axe-core/playwright test for this page (tags wcag2a, wcag2aa, wcag22aa).
Prefer native elements over ARIA. Do not change the visual design beyond what a fix requires.Audit <page or component> for accessibility and fix what you find. Work through this list in order and report each item as PASS / FIXED / NEEDS HUMAN:
1. Actions use <button>, navigation uses <a href>; no clickable div/span.
2. Every interactive element has a visible :focus-visible style; no bare outline:none.
3. Icon-only controls have an accessible name (aria-label or visually hidden text).
4. Text contrast ≥ 4.5:1 (3:1 for large text and UI parts) in light AND dark themes; list the ratios.
5. Touch targets ≥ 24×24 CSS px or adequately spaced.
6. Dialogs/menus: focus moves in on open, Tab stays inside, Escape closes, focus returns to the trigger.
7. Every input has a programmatic label; errors linked with aria-describedby; no placeholder-as-label.
8. Status messages (saved, results count, errors) use role="status" or aria-live.
9. Headings form a logical outline; images have meaningful alt or alt="".
Then add an @axe-core/playwright test for this page (tags wcag2a, wcag2aa, wcag22aa).
Prefer native elements over ARIA. Do not change the visual design beyond what a fix requires.Audit <page or component> for accessibility and fix what you find. Work through this list in order and report each item as PASS / FIXED / NEEDS HUMAN:
1. Actions use <button>, navigation uses <a href>; no clickable div/span.
2. Every interactive element has a visible :focus-visible style; no bare outline:none.
3. Icon-only controls have an accessible name (aria-label or visually hidden text).
4. Text contrast ≥ 4.5:1 (3:1 for large text and UI parts) in light AND dark themes; list the ratios.
5. Touch targets ≥ 24×24 CSS px or adequately spaced.
6. Dialogs/menus: focus moves in on open, Tab stays inside, Escape closes, focus returns to the trigger.
7. Every input has a programmatic label; errors linked with aria-describedby; no placeholder-as-label.
8. Status messages (saved, results count, errors) use role="status" or aria-live.
9. Headings form a logical outline; images have meaningful alt or alt="".
Then add an @axe-core/playwright test for this page (tags wcag2a, wcag2aa, wcag22aa).
Prefer native elements over ARIA. Do not change the visual design beyond what a fix requires.Audit <page or component> for accessibility and fix what you find. Work through this list in order and report each item as PASS / FIXED / NEEDS HUMAN:
1. Actions use <button>, navigation uses <a href>; no clickable div/span.
2. Every interactive element has a visible :focus-visible style; no bare outline:none.
3. Icon-only controls have an accessible name (aria-label or visually hidden text).
4. Text contrast ≥ 4.5:1 (3:1 for large text and UI parts) in light AND dark themes; list the ratios.
5. Touch targets ≥ 24×24 CSS px or adequately spaced.
6. Dialogs/menus: focus moves in on open, Tab stays inside, Escape closes, focus returns to the trigger.
7. Every input has a programmatic label; errors linked with aria-describedby; no placeholder-as-label.
8. Status messages (saved, results count, errors) use role="status" or aria-live.
9. Headings form a logical outline; images have meaningful alt or alt="".
Then add an @axe-core/playwright test for this page (tags wcag2a, wcag2aa, wcag22aa).
Prefer native elements over ARIA. Do not change the visual design beyond what a fix requires.Audit <page or component> for accessibility and fix what you find. Work through this list in order and report each item as PASS / FIXED / NEEDS HUMAN:
1. Actions use <button>, navigation uses <a href>; no clickable div/span.
2. Every interactive element has a visible :focus-visible style; no bare outline:none.
3. Icon-only controls have an accessible name (aria-label or visually hidden text).
4. Text contrast ≥ 4.5:1 (3:1 for large text and UI parts) in light AND dark themes; list the ratios.
5. Touch targets ≥ 24×24 CSS px or adequately spaced.
6. Dialogs/menus: focus moves in on open, Tab stays inside, Escape closes, focus returns to the trigger.
7. Every input has a programmatic label; errors linked with aria-describedby; no placeholder-as-label.
8. Status messages (saved, results count, errors) use role="status" or aria-live.
9. Headings form a logical outline; images have meaningful alt or alt="".
Then add an @axe-core/playwright test for this page (tags wcag2a, wcag2aa, wcag22aa).
Prefer native elements over ARIA. Do not change the visual design beyond what a fix requires.Audit <page or component> for accessibility and fix what you find. Work through this list in order and report each item as PASS / FIXED / NEEDS HUMAN:
1. Actions use <button>, navigation uses <a href>; no clickable div/span.
2. Every interactive element has a visible :focus-visible style; no bare outline:none.
3. Icon-only controls have an accessible name (aria-label or visually hidden text).
4. Text contrast ≥ 4.5:1 (3:1 for large text and UI parts) in light AND dark themes; list the ratios.
5. Touch targets ≥ 24×24 CSS px or adequately spaced.
6. Dialogs/menus: focus moves in on open, Tab stays inside, Escape closes, focus returns to the trigger.
7. Every input has a programmatic label; errors linked with aria-describedby; no placeholder-as-label.
8. Status messages (saved, results count, errors) use role="status" or aria-live.
9. Headings form a logical outline; images have meaningful alt or alt="".
Then add an @axe-core/playwright test for this page (tags wcag2a, wcag2aa, wcag22aa).
Prefer native elements over ARIA. Do not change the visual design beyond what a fix requires.引用来源引用來源References参考文献참고 자료RujukanNguồn tham khảoRéférencesReferenciasQuellen
- Web Content Accessibility Guidelines (WCAG) 2.2 — W3C
- ARIA Authoring Practices Guide — W3C WAI
- Radix Primitives introduction — Radix
- Web Interface Guidelines — Vercel
- Understanding SC 2.5.8 Target Size (Minimum) — W3C WAI
- Dialog (Modal) pattern — W3C WAI APG
- :focus-visible — MDN
- axe-core — Deque
- Accessibility testing — Playwright
- The WebAIM Million — WebAIM
相关文章相關文章Related posts関連記事관련 글Artikel berkaitanBài liên quanArticles liésArtículos relacionadosÄhnliche Beiträge

让动效"对味":目的、时长、缓动与克制讓動效「對味」:目的、時長、緩動與克制Motion that feels right: purpose, duration, easing, restraintしっくりくるモーション:目的・時間・イージング・抑制자연스러운 모션: 목적, 시간, 이징, 절제Gerakan yang terasa betul: tujuan, tempoh, easing, kawalanChuyển động đúng cảm giác: mục đích, thời lượng, easing, tiết chếUn mouvement juste : intention, durée, easing, retenueMovimiento que se siente bien: propósito, duración, easing, contenciónBewegung, die sich richtig anfühlt: Zweck, Dauer, Easing, Zurückhaltung
大多数界面动效应在 300ms 内、用 ease-out,高频操作干脆不做。炫技属于营销页,不属于工具。大多數介面動效應在 300ms 內、用 ease-out,高頻操作乾脆不做。Most UI motion should be under 300ms, ease-out, and skipped for frequent actions. Spectacle belongs on marketing pages, not in tools.UIモーションは300ms以内・ease-out、頻繁な操作には付けない。UI 모션은 300ms 이하, ease-out, 잦은 동작엔 생략.Kebanyakan gerakan UI di bawah 300ms, ease-out, dan dilangkau untuk tindakan kerap.Hầu hết chuyển động dưới 300ms, ease-out, bỏ qua với thao tác thường xuyên.Moins de 300 ms, ease-out, et rien pour les actions fréquentes.Menos de 300 ms, ease-out, y nada en acciones frecuentes.Unter 300 ms, ease-out, und keine Animation für häufige Aktionen.

把暗色模式做对:token、层级与对比度把暗色模式做對:token、層級與對比度Dark mode done right: tokens, elevation and contrast正しいダークモード:トークン・階層・コントラスト다크 모드 제대로: 토큰, 고도, 대비Mod gelap yang betul: token, ketinggian dan kontrasLàm dark mode đúng: token, độ nổi và độ tương phảnUn mode sombre réussi : tokens, élévation et contrasteModo oscuro bien hecho: tokens, elevación y contrasteDark Mode richtig: Tokens, Elevation und Kontrast
暗色模式是第二套配色,不是反色。用语义 token,用更亮的表面表达层级,强调色要降饱和。暗色模式是第二套配色,不是反色。用語義 token,用更亮的表面表達層級。Dark mode is a second palette, not an inverted one. Use semantic tokens, lighter surfaces for elevation, and desaturated accents.ダークモードは反転ではなく第二のパレット。意味トークン、明るい面で階層、彩度を下げたアクセント。다크 모드는 반전이 아니라 두 번째 팔레트. 시맨틱 토큰, 밝은 면으로 고도 표현.Mod gelap ialah palet kedua, bukan terbalik. Guna token semantik dan permukaan lebih cerah untuk ketinggian.Dark mode là bảng màu thứ hai, không phải đảo màu. Dùng token ngữ nghĩa, bề mặt sáng hơn để thể hiện độ nổi.Une seconde palette, pas une inversion. Tokens sémantiques, surfaces plus claires pour l'élévation.Una segunda paleta, no una inversión. Tokens semánticos y superficies más claras para la elevación.Eine zweite Palette, keine Invertierung. Semantische Tokens, hellere Flächen für Elevation.

AI 生成界面的字体排印:摆脱平庸感最快的办法AI 產生介面的字體排印:擺脫平庸感最快的辦法Typography for AI-generated UI: the fastest way to look less genericAI生成UIのタイポグラフィ:没個性から抜け出す最短路AI 생성 UI의 타이포그래피: 평범함을 벗는 가장 빠른 길Tipografi untuk UI jana AITypography cho UI do AI tạo: cách nhanh nhất để bớt tầm thườngLa typographie des UI générées par IATipografía para UI generada por IATypografie für KI-generierte UIs
生成器默认一种无衬线、三个字号。一套字号阶梯、第二种字体、大字号收紧字距和合理行长,能解决大部分问题。產生器預設一種無襯線、三個字級。一套字級階梯、第二種字體、大字收緊字距和合理行長,能解決大部分問題。Generators default to one sans at three sizes. A type scale, a second typeface, tighter tracking on display sizes and real line lengths fix most of it.生成器は1書体3サイズが既定。スケール、第2書体、見出しの字詰め、行長で大半が直る。생성기는 산세리프 하나에 크기 셋. 스케일, 두 번째 서체, 자간, 줄 길이로 대부분 해결.Skala jenis, muka taip kedua, jarak huruf dan panjang baris menyelesaikan kebanyakannya.Thang cỡ chữ, font thứ hai, giãn chữ và độ dài dòng giải quyết phần lớn.Une échelle, une seconde police, l'approche et la longueur de ligne règlent l'essentiel.Una escala, una segunda fuente, el tracking y la longitud de línea resuelven casi todo.Skala, zweite Schrift, Laufweite und Zeilenlänge lösen das meiste.