a11y-debugging

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Core Concepts

核心概念

Accessibility Tree vs DOM: Visually hiding an element (e.g.,
CSS opacity: 0
) behaves differently for screen readers than
display: none
or
aria-hidden="true"
. The
take_snapshot
tool returns the accessibility tree of the page, which represents what assistive technologies "see", making it the most reliable source of truth for semantic structure.
Reading web.dev documentation: If you need to research specific accessibility guidelines (like
https://web.dev/articles/accessible-tap-targets
), you can append
.md.txt
to the URL (e.g.,
https://web.dev/articles/accessible-tap-targets.md.txt
) to fetch the clean, raw markdown version. This is much easier to read!
无障碍树与DOM的区别:通过CSS
opacity: 0
视觉隐藏元素的方式,在屏幕阅读器中的表现与
display: none
aria-hidden="true"
不同。
take_snapshot
工具会返回页面的无障碍树,它代表了辅助技术所“感知”到的内容,是语义化结构最可靠的参考依据。
查阅web.dev文档:如果你需要研究特定的无障碍指南(如
https://web.dev/articles/accessible-tap-targets
),可以在URL后追加
.md.txt
(例如
https://web.dev/articles/accessible-tap-targets.md.txt
)来获取干净的原始markdown版本,这样阅读起来会轻松很多!

Workflow Patterns

工作流模式

1. Browser Issues & Audits

1. 浏览器问题与审计

Chrome automatically checks for common accessibility problems. Use
list_console_messages
to check for these native audits first:
  • types
    :
    ["issue"]
  • includePreservedMessages
    :
    true
    (to catch issues that occurred during page load)
This often reveals missing labels, invalid ARIA attributes, and other critical errors without manual investigation.
Chrome会自动检查常见的无障碍问题。首先使用
list_console_messages
工具查看这些原生审计结果:
  • types
    :
    ["issue"]
  • includePreservedMessages
    :
    true
    (捕获页面加载过程中出现的问题)
这通常无需手动排查就能发现缺失的标签、无效的ARIA属性以及其他关键错误。

2. Semantics & Structure

2. 语义化与结构

The accessibility tree exposes the heading hierarchy and semantic landmarks.
  1. Navigate to the page.
  2. Use
    take_snapshot
    to capture the accessibility tree.
  3. Check Heading Levels: Ensure heading levels (
    h1
    ,
    h2
    ,
    h3
    , etc.) are logical and do not skip levels. The snapshot will include heading roles.
  4. Content Reordering: Verify that the DOM order (which drives the accessibility tree) matches the visual reading order. Use
    take_screenshot
    to inspect the visual layout and compare it against the snapshot structure to catch CSS floats or absolute positioning that jumbles the logical flow.
无障碍树会暴露标题层级和语义化地标信息。
  1. 导航至目标页面。
  2. 使用
    take_snapshot
    工具捕获页面的无障碍树。
  3. 检查标题层级:确保标题层级(
    h1
    h2
    h3
    等)符合逻辑,不存在层级跳跃。快照中会包含标题角色信息。
  4. 内容顺序验证:确认DOM顺序(决定无障碍树的结构)与视觉阅读顺序一致。使用
    take_screenshot
    工具检查视觉布局,并与快照结构对比,排查因CSS浮动或绝对定位导致的逻辑顺序混乱问题。

3. Labels, Forms & Text Alternatives

3. 标签、表单与文本替代方案

  1. Locate buttons, inputs, and images in the
    take_snapshot
    output.
  2. Ensure interactive elements have an accessible name (e.g., a button should not just say
    ""
    if it only contains an icon).
  3. Orphaned Inputs: Verify that all form inputs have associated labels. Use
    evaluate_script
    to check for inputs missing
    id
    (for
    label[for]
    ) or
    aria-label
    :
    js
    () =>
      Array.from(document.querySelectorAll('input, select, textarea'))
        .filter(i => {
          const hasId = i.id && document.querySelector(`label[for="${i.id}"]`);
          const hasAria =
            i.getAttribute('aria-label') || i.getAttribute('aria-labelledby');
          return !hasId && !hasAria && !i.closest('label');
        })
        .map(i => ({
          tag: i.tagName,
          id: i.id,
          name: i.name,
          placeholder: i.placeholder,
        }));

4.  Check images for `alt` text.
  1. take_snapshot
    工具的输出中定位按钮、输入框和图片元素。
  2. 确保交互元素具备无障碍名称(例如,仅包含图标的按钮不能显示为空字符串
    ""
    )。
  3. 孤立输入框检查:验证所有表单输入框都关联了标签。使用
    evaluate_script
    工具检查缺失
    id
    (用于
    label[for]
    关联)或
    aria-label
    的输入框:
    js
    () =>
      Array.from(document.querySelectorAll('input, select, textarea'))
        .filter(i => {
          const hasId = i.id && document.querySelector(`label[for=\"${i.id}\"]`);
          const hasAria =
            i.getAttribute('aria-label') || i.getAttribute('aria-labelledby');
          return !hasId && !hasAria && !i.closest('label');
        })
        .map(i => ({
          tag: i.tagName,
          id: i.id,
          name: i.name,
          placeholder: i.placeholder,
        }));
  4. 检查图片是否包含
    alt
    文本。

4. Focus & Keyboard Navigation

4. 焦点与键盘导航

Testing "keyboard traps" and proper focus management without visual feedback relies on tracking the focused element.
  1. Use the
    press_key
    tool with
    "Tab"
    or
    "Shift+Tab"
    to move focus.
  2. Use
    take_snapshot
    to capture the updated accessibility tree.
  3. Locate the element marked as focused in the snapshot to verify focus moved to the expected interactive element.
  4. If a modal opens, focus must move into the modal and "trap" within it until closed.
测试“键盘陷阱”和无视觉反馈的焦点管理时,需要跟踪当前聚焦的元素。
  1. 使用
    press_key
    工具,传入
    "Tab"
    "Shift+Tab"
    来移动焦点。
  2. 使用
    take_snapshot
    工具捕获更新后的无障碍树。
  3. 在快照中找到标记为聚焦的元素,验证焦点是否移动到了预期的交互元素上。
  4. 若模态框弹出,焦点必须移入模态框内,并在关闭前“锁定”在模态框中。

5. Tap Targets and Visuals

5. 点击目标与视觉元素

According to web.dev, tap targets should be at least 48x48 pixels with sufficient spacing. Since the accessibility tree doesn't show sizes, use
evaluate_script
:
js
// Usage in console: copy, paste, and call with element: fn(element)
el => {
 const rect = el.getBoundingClientRect();
 return {width: rect.width, height: rect.height};
};
Pass the element's
uid
from the snapshot as an argument to
evaluate_script
.
根据web.dev的规范,点击目标的尺寸至少应为48x48像素,且间距充足。由于无障碍树不显示元素尺寸,可使用
evaluate_script
工具:
js
// 控制台使用方式:复制、粘贴并传入元素调用:fn(element)
el => {
 const rect = el.getBoundingClientRect();
 return {width: rect.width, height: rect.height};
};
传入快照中元素的
uid
作为
evaluate_script
工具的参数。

6. Color Contrast

6. 颜色对比度

To verify color contrast ratios, start by checking for native accessibility issues:
  1. Call
    list_console_messages
    with
    types: ["issue"]
    .
  2. Look for "Low Contrast" issues in the output.
If native audits do not report issues (which may happen in some headless environments) or if you need to check a specific element manually, you can use the following script as a fallback approximation.
Note: This script uses a simplified algorithm and may not account for transparency, gradients, or background images. For production-grade auditing, consider injecting
axe-core
.
js
el => {
  function getRGB(colorStr) {
    const match = colorStr.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);
    return match
      ? [parseInt(match[1]), parseInt(match[2]), parseInt(match[3])]
      : [255, 255, 255];
  }
  function luminance(r, g, b) {
    const a = [r, g, b].map(function (v) {
      v /= 255;
      return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
    });
    return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722;
  }

  const style = window.getComputedStyle(el);
  const fg = getRGB(style.color);
  let bg = getRGB(style.backgroundColor);

  // Basic contrast calculation (Note: Doesn't account for transparency over background images)
  const l1 = luminance(fg[0], fg[1], fg[2]);
  const l2 = luminance(bg[0], bg[1], bg[2]);
  const ratio = (Math.max(l1, l2) + 0.05) / (Math.min(l1, l2) + 0.05);

  return {
    color: style.color,
    bg: style.backgroundColor,
    contrastRatio: ratio.toFixed(2),
  };
};
Pass the element's
uid
to test the contrast against WCAG AA (4.5:1 for normal text, 3:1 for large text).
要验证颜色对比度,首先检查原生无障碍问题:
  1. 调用
    list_console_messages
    工具,传入
    types: ["issue"]
  2. 在输出中查找“低对比度”问题。
如果原生审计未报告问题(在部分无头环境中可能出现这种情况),或者你需要手动检查特定元素,可以使用以下脚本作为备选方案。
注意:该脚本使用简化算法,可能未考虑透明度、渐变或背景图片的影响。如需生产级别的审计,建议注入
axe-core
工具。
js
el => {
  function getRGB(colorStr) {
    const match = colorStr.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);
    return match
      ? [parseInt(match[1]), parseInt(match[2]), parseInt(match[3])]
      : [255, 255, 255];
  }
  function luminance(r, g, b) {
    const a = [r, g, b].map(function (v) {
      v /= 255;
      return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
    });
    return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722;
  }

  const style = window.getComputedStyle(el);
  const fg = getRGB(style.color);
  let bg = getRGB(style.backgroundColor);

  // 基础对比度计算(注意:未考虑背景图片上的透明度影响)
  const l1 = luminance(fg[0], fg[1], fg[2]);
  const l2 = luminance(bg[0], bg[1], bg[2]);
  const ratio = (Math.max(l1, l2) + 0.05) / (Math.min(l1, l2) + 0.05);

  return {
    color: style.color,
    bg: style.backgroundColor,
    contrastRatio: ratio.toFixed(2),
  };
};
传入元素的
uid
,测试其对比度是否符合WCAG AA标准(普通文本要求4.5:1,大文本要求3:1)。

7. Global Page Checks

7. 全局页面检查

Verify document-level accessibility settings often missed in component testing:
js
() => ({
  lang:
    document.documentElement.lang ||
    'MISSING - Screen readers need this for pronunciation',
  title: document.title || 'MISSING - Required for context',
  viewport:
    document.querySelector('meta[name="viewport"]')?.content ||
    'MISSING - Check for user-scalable=no (bad practice)',
  reducedMotion: window.matchMedia('(prefers-reduced-motion: reduce)').matches
    ? 'Enabled'
    : 'Disabled',
});
验证组件测试中常被忽略的文档级无障碍设置:
js
() => ({
  lang:
    document.documentElement.lang ||
    'MISSING - Screen readers need this for pronunciation',
  title: document.title || 'MISSING - Required for context',
  viewport:
    document.querySelector('meta[name=\"viewport\"]')?.content ||
    'MISSING - Check for user-scalable=no (bad practice)',
  reducedMotion: window.matchMedia('(prefers-reduced-motion: reduce)').matches
    ? 'Enabled'
    : 'Disabled',
});

Troubleshooting

故障排除

If standard a11y queries fail or the
evaluate_script
snippets return unexpected results:
  • Visual Inspection: If automated scripts cannot determine contrast (e.g., text over gradient images or complex backgrounds), use
    take_screenshot
    to capture the element. While models cannot measure exact contrast ratios from images, they can visually assess legibility and identifying obvious issues.
如果标准的a11y查询失败,或
evaluate_script
代码片段返回意外结果:
  • 视觉检查:如果自动化脚本无法判断对比度(例如文本覆盖在渐变图片或复杂背景上),使用
    take_screenshot
    工具捕获元素。虽然模型无法从图片中测量精确的对比度,但可以通过视觉评估可读性并识别明显问题。