文档可访问性技能Skill docs-accessibility

文档可访问性验证与修复工具,用于检查WCAG合规性、验证图像替代文本、分析标题结构、测试颜色对比度,生成详细可访问性报告。关键词:文档可访问性、WCAG合规、无障碍测试、替代文本验证、标题层级分析、颜色对比度检查、键盘导航测试、屏幕阅读器兼容、ARIA地标、可访问性审计

测试 0 次安装 0 次浏览 更新于 2/26/2026

name: docs-accessibility description: 文档可访问性验证与修复。检查WCAG 2.1合规性,验证替代文本,分析标题层级,验证颜色对比度,并生成可访问性报告。 allowed-tools: Read, Write, Edit, Bash, Glob, Grep backlog-id: SK-019 metadata: author: babysitter-sdk version: “1.0.0”

文档可访问性技能

文档可访问性验证与修复。

功能

  • WCAG 2.1合规性检查
  • 图像替代文本验证
  • 标题层级分析
  • 颜色对比度验证
  • 屏幕阅读器兼容性测试
  • 键盘导航验证
  • ARIA地标检查
  • 可访问性报告生成

使用场景

在以下情况下调用此技能:

  • 审核文档的可访问性
  • 验证图像替代文本
  • 检查标题结构
  • 验证颜色对比度比率
  • 生成可访问性报告

输入参数

参数 类型 必填 描述
inputPath string 文档或构建站点的路径
action string audit, validate-images, check-headings
standard string WCAG级别 (A, AA, AAA)
outputFormat string json, html, sarif
fix boolean 自动修复可能的问题

输入示例

{
  "inputPath": "./docs/_build/html",
  "action": "audit",
  "standard": "AA",
  "outputFormat": "json"
}

输出结构

可访问性报告

{
  "summary": {
    "total": 156,
    "passed": 142,
    "failed": 14,
    "level": "AA",
    "score": 91
  },
  "byCategory": {
    "images": { "passed": 45, "failed": 3 },
    "headings": { "passed": 28, "failed": 2 },
    "contrast": { "passed": 52, "failed": 5 },
    "navigation": { "passed": 17, "failed": 4 }
  },
  "issues": [
    {
      "id": "img-alt-missing",
      "wcag": "1.1.1",
      "level": "A",
      "impact": "critical",
      "description": "图像缺少替代文本",
      "location": {
        "file": "docs/guide/setup.md",
        "line": 42,
        "element": "<img src=\"diagram.png\">"
      },
      "suggestion": "添加描述性替代文本:alt=\"系统架构图显示...\""
    },
    {
      "id": "heading-skip",
      "wcag": "1.3.1",
      "level": "A",
      "impact": "moderate",
      "description": "标题级别应仅增加一级",
      "location": {
        "file": "docs/api/users.md",
        "line": 15,
        "element": "<h4>用户属性</h4>"
      },
      "context": "H2 -> H4 (跳过H3)",
      "suggestion": "更改为<h3>或在上面添加缺失的<h3>"
    },
    {
      "id": "color-contrast",
      "wcag": "1.4.3",
      "level": "AA",
      "impact": "serious",
      "description": "文本不符合对比度要求",
      "location": {
        "file": "docs/_static/custom.css",
        "line": 28,
        "element": ".note { color: #999; }"
      },
      "details": {
        "foreground": "#999999",
        "background": "#ffffff",
        "ratio": "2.85:1",
        "required": "4.5:1"
      },
      "suggestion": "更改为#767676或更深的颜色以达到4.5:1对比度"
    }
  ],
  "wcagCompliance": {
    "A": { "passed": 48, "failed": 6 },
    "AA": { "passed": 35, "failed": 8 },
    "AAA": { "passed": 12, "failed": 0 }
  }
}

检查的WCAG指南

可感知性(原则1)

1.1.1 - 非文本内容:
  - 图像有替代文本
  - 装饰性图像有空替代文本
  - 复杂图像有长描述
  - 图标有可访问名称

1.3.1 - 信息和关系:
  - 标题结构正确
  - 列表正确标记
  - 表格有表头
  - 表单标签关联

1.4.1 - 颜色的使用:
  - 颜色不是唯一指示器
  - 链接可区分

1.4.3 - 对比度(最低):
  - 文本:4.5:1比率
  - 大文本:3:1比率
  - UI组件:3:1比率

可操作性(原则2)

2.1.1 - 键盘:
  - 所有功能可通过键盘访问
  - 无键盘陷阱
  - 存在跳过链接

2.4.1 - 绕过块:
  - 跳过导航链接
  - 地标区域

2.4.2 - 页面标题:
  - 描述性页面标题

2.4.6 - 标题和标签:
  - 描述性标题
  - 清晰标签

2.4.7 - 焦点可见:
  - 可见焦点指示器

可理解性(原则3)

3.1.1 - 页面语言:
  - 存在lang属性

3.2.3 - 一致性导航:
  - 跨页面导航一致

3.3.2 - 标签或说明:
  - 表单输入有标签

图像替代文本验证

替代文本规则

const altTextRules = {
  // 必须有alt属性
  required: {
    test: (img) => img.hasAttribute('alt'),
    message: '图像必须有alt属性'
  },

  // 替代文本应具有描述性
  descriptive: {
    test: (img) => {
      const alt = img.getAttribute('alt');
      const badPatterns = [
        /^image$/i,
        /^photo$/i,
        /^picture$/i,
        /^graphic$/i,
        /\.(?:png|jpg|gif|svg)$/i,
        /^untitled/i
      ];
      return !badPatterns.some(p => p.test(alt));
    },
    message: '替代文本应描述图像内容'
  },

  // 不要太长
  length: {
    test: (img) => {
      const alt = img.getAttribute('alt');
      return alt.length <= 125;
    },
    message: '替代文本应简洁(少于125个字符)'
  },

  // 装饰性图像应有空替代文本
  decorative: {
    test: (img) => {
      if (img.hasAttribute('role') && img.getAttribute('role') === 'presentation') {
        return img.getAttribute('alt') === '';
      }
      return true;
    },
    message: '装饰性图像应有空alt=""'
  }
};

替代文本建议

function suggestAltText(imagePath, context) {
  const suggestions = [];

  // 基于文件名
  const filename = path.basename(imagePath, path.extname(imagePath));
  if (filename.includes('diagram')) {
    suggestions.push(`显示${extractContext(context)}的图表`);
  }
  if (filename.includes('screenshot')) {
    suggestions.push(`${extractContext(context)}的截图`);
  }
  if (filename.includes('logo')) {
    suggestions.push(`${extractBrand(filename)}标志`);
  }

  // 基于周围文本
  const heading = findNearestHeading(context);
  if (heading) {
    suggestions.push(`${heading}的插图`);
  }

  return suggestions;
}

标题结构分析

标题层级检查

function analyzeHeadings(content) {
  const headings = extractHeadings(content);
  const issues = [];

  let lastLevel = 0;
  headings.forEach((heading, index) => {
    const level = heading.level;

    // 检查跳过的级别
    if (level > lastLevel + 1 && lastLevel !== 0) {
      issues.push({
        type: 'heading-skip',
        heading: heading.text,
        line: heading.line,
        expected: lastLevel + 1,
        actual: level
      });
    }

    // 检查多个H1
    if (level === 1 && index > 0) {
      issues.push({
        type: 'multiple-h1',
        heading: heading.text,
        line: heading.line
      });
    }

    lastLevel = level;
  });

  return {
    structure: buildHeadingTree(headings),
    issues
  };
}

颜色对比度检查

对比度比率计算

function getContrastRatio(foreground, background) {
  const fgLuminance = getRelativeLuminance(foreground);
  const bgLuminance = getRelativeLuminance(background);

  const lighter = Math.max(fgLuminance, bgLuminance);
  const darker = Math.min(fgLuminance, bgLuminance);

  return (lighter + 0.05) / (darker + 0.05);
}

function meetsContrastRequirement(ratio, isLargeText, level = 'AA') {
  const requirements = {
    'AA': { normal: 4.5, large: 3 },
    'AAA': { normal: 7, large: 4.5 }
  };

  const threshold = isLargeText
    ? requirements[level].large
    : requirements[level].normal;

  return ratio >= threshold;
}

CSS分析

async function analyzeStylesheet(cssPath) {
  const css = await fs.readFile(cssPath, 'utf8');
  const ast = postcss.parse(css);
  const issues = [];

  ast.walkDecls('color', (decl) => {
    const rule = decl.parent;
    const bgColor = findBackgroundColor(rule) || '#ffffff';
    const fgColor = decl.value;

    const ratio = getContrastRatio(fgColor, bgColor);

    if (!meetsContrastRequirement(ratio, false, 'AA')) {
      issues.push({
        selector: rule.selector,
        foreground: fgColor,
        background: bgColor,
        ratio: ratio.toFixed(2),
        line: decl.source.start.line,
        suggestion: suggestAccessibleColor(fgColor, bgColor)
      });
    }
  });

  return issues;
}

键盘导航

焦点测试

async function testKeyboardNavigation(page) {
  const issues = [];

  // 获取所有可聚焦元素
  const focusable = await page.$$('a, button, input, select, textarea, [tabindex]');

  for (const element of focusable) {
    await element.focus();

    // 检查焦点可见性
    const hasFocusStyle = await page.evaluate((el) => {
      const styles = window.getComputedStyle(el);
      const focusStyles = window.getComputedStyle(el, ':focus');
      return (
        styles.outline !== 'none' ||
        styles.boxShadow !== 'none' ||
        focusStyles.outline !== 'none'
      );
    }, element);

    if (!hasFocusStyle) {
      issues.push({
        type: 'focus-not-visible',
        element: await element.evaluate(el => el.outerHTML.substring(0, 100))
      });
    }
  }

  return issues;
}

工作流程

  1. 解析内容 - 加载文档文件或构建的HTML
  2. 提取元素 - 查找图像、标题、链接等
  3. 检查图像 - 验证替代文本
  4. 分析标题 - 检查层级结构
  5. 测试对比度 - 验证颜色比率
  6. 检查导航 - 验证键盘访问
  7. 生成报告 - 输出发现

依赖项

{
  "devDependencies": {
    "axe-core": "^4.8.0",
    "pa11y": "^6.2.0",
    "lighthouse": "^11.0.0",
    "puppeteer": "^21.0.0",
    "color-contrast-checker": "^2.1.0"
  }
}

CLI命令

# 运行axe-core审核
npx axe ./docs/_build/html --rules wcag2aa

# 运行pa11y
npx pa11y https://docs.example.com --standard WCAG2AA

# Lighthouse可访问性审核
npx lighthouse https://docs.example.com --only-categories=accessibility

# 检查单个页面
npx axe https://docs.example.com/guide --save report.json

应用的最佳实践

  • 始终为信息性图像提供替代文本
  • 装饰性图像使用空替代文本
  • 保持逻辑标题层级
  • 确保普通文本4.5:1对比度
  • 提供可见焦点指示器
  • 包含跳过导航链接
  • 使用语义HTML元素

参考资料

目标流程

  • docs-testing.js
  • docs-audit.js
  • style-guide-enforcement.js