Front-End-Checklist 规则实战:为图片提供有意义的 alt 文本(alt-text 规则全解)
本文基于 Front-End-Checklist 仓库中的 alt-text 规则参考文档,系统讲解图片可访问性的核心机制:为什么每个 <img> 都必须有 alt 属性、不同角色(信息性、装饰性、链接、纯文字、复杂图表)的图片应如何取值、如何在 React/Next.js 中落地,以及如何用 axe、Lighthouse 和屏幕阅读器完成验证。读完后,你既能手动修复图片 alt 问题,也能理解该规则在仓库中从 MDX 源文件到 Agent 可安装 skill 的完整生成链路。
规则定位与元信息
alt 属性是图片可访问性的首要机制。规则文档给出的定位是:每个 <img> 都必须有 alt 属性,其取值取决于图片在页面中所扮演的角色(见 rules 正文)。
该规则的元信息(定义在源 MDX 的 frontmatter 中,见 alt-text.mdx):
| 字段 | 值 | 含义 |
|---|---|---|
priority |
critical |
最高优先级,属于必须修复的问题 |
difficulty |
beginner |
入门难度,改动通常是加一个属性 |
estimatedTime |
15 min |
单个页面的典型修复耗时 |
categories |
images / accessibility |
归类于图片类规则,子类别为可访问性 |
为什么是 critical 优先级? 文档给出了三层依据:
- 规模:全球约有 22 亿人存在视力障碍,屏幕阅读器会逐字朗读
alt属性——没有有意义的 alt,视障用户对图片内容一无所知; - 合规:缺失 alt 直接违反 WCAG 2.1 Success Criterion 1.1.1(非文本内容),这是 Level A(最低级)要求,合规基线的第一道门槛;
- SEO:搜索引擎同样依赖 alt 文本来索引图片内容。
核心原则:alt 描述"图片传达了什么",而不是"图片长什么样"
文档用一个营收图表的例子完整展示了四种典型错误与正确写法:
<!-- ❌ Bad: Missing alt -->
<img src="revenue-chart.png">
<!-- ❌ Bad: Filename as alt -->
<img src="revenue-chart.png" alt="revenue-chart.png">
<!-- ❌ Bad: Generic alt -->
<img src="revenue-chart.png" alt="chart">
<!-- ✅ Good: Describes what the image conveys -->
<img
src="revenue-chart.png"
alt="Bar chart showing Q3 2024 revenue increased 40% year-over-year, reaching $2.4M"
>
四个反例覆盖了真实代码库中最常见的失误模式:完全缺失、文件名当 alt、泛化 alt(alt="image"、alt="photo")。规则文档明确指出,糟糕的 alt(如 alt="image")与没有 alt 没有本质区别——它占用了属性位却不传递任何信息。判断某张图该取什么值时,文档建议参照 W3C 官方的 alt 决策树(该决策树也列在源 MDX 的 resources 字段 中)。
四类特殊场景的取值策略
规则文档把图片按角色分为四类特殊场景,每类有独立的取值策略,这也是修复工作的核心决策树。
装饰性图片:alt="" 显式隐藏
纯粹用于视觉装饰的图片不承载信息,应让辅助技术完全跳过。关键点在于 alt=""(空字符串)与省略 alt 行为完全不同:
<!-- ❌ Bad: No alt attribute—screen reader may announce the filename -->
<img src="decorative-swirl.png">
<!-- ✅ Good: Empty alt hides image from screen readers -->
<img src="decorative-swirl.png" alt="">
<!-- ✅ Good: Or use CSS background images for decoration -->
<div class="decorative-swirl" aria-hidden="true"></div>
省略 alt 时,部分屏幕阅读器会朗读文件名(如 "decorative-swirl.png"),反而制造噪声。文档还给出第三条路线:纯装饰效果直接用 CSS 背景图 + aria-hidden="true" 容器。仓库中生成的全局审计 skill 也印证了这一立场——generate-skills.ts 中明确要求审计时"不要把 alt="" 默认当问题",把 <img ... alt="" aria-hidden="true"> 视为零问题安全模式(Zero-issue pattern)。
作为链接的图片:alt 描述链接目的地
当 <img> 被包在 <a> 里时,图片承担的是"链接"角色,屏幕阅读器朗读的是 alt + "链接",因此 alt 应描述跳转目标而非视觉外观:
<!-- ❌ Bad: Describes appearance, not destination -->
<a href="https://twitter.com/example">
<img src="twitter-logo.svg" alt="Blue bird logo">
</a>
<!-- ✅ Good: Describes the link destination -->
<a href="https://twitter.com/example">
<img src="twitter-logo.svg" alt="Follow us on Twitter">
</a>
文字图片:alt 逐字复刻图中文字
图片本身承载文字(logo、横幅、截图)时,alt 应逐字(verbatim)复刻其中的文字,让屏幕阅读器用户获得与视觉用户一致的内容:
<!-- ✅ Good: Alt reproduces the text shown in the image -->
<img src="sale-banner.png" alt="Summer Sale — 50% off all items">
<!-- ✅ Good: Logo with company name -->
<img src="logo.svg" alt="Acme Corp">
复杂图片(图表、示意图):短 alt + 长描述
复杂视觉内容无法在一行 alt 内说清,策略是"简短 alt + 对所有用户可见的长描述"。文档给出的实现是用 aria-describedby 关联一个可见的 figcaption:
<!-- Using aria-describedby to link to a visible description -->
<figure>
<img
src="org-chart.png"
alt="Company organisational chart"
aria-describedby="org-chart-desc"
>
<figcaption id="org-chart-desc">
The chart shows three departments reporting to the CEO: Engineering (12 staff),
Marketing (8 staff), and Operations (5 staff).
</figcaption>
</figure>
这种"可见描述 + aria-describedby"的组合是刻意设计:长描述放在 <figcaption> 里让所有用户都能读到(而非仅屏幕阅读器),aria-describedby 则保证朗读顺序自然衔接。这也解释了源 MDX 中 relatedRules 字段 为何把 figure-figcaption 列为第一条关联规则——两条规则在复杂图片场景下天然成对出现。
框架落地:React 与 Next.js 示例
规则文档提供了两套框架级写法,核心思想是把"装饰性 → 空字符串"的决策固化进组件 API,从类型层面杜绝忘记传 alt。
React 组件封装(装饰性走 decorative 布尔开关):
interface ImageProps {
src: string
alt: string
decorative?: boolean
}
function AccessibleImage({ src, alt, decorative = false }: ImageProps) {
return (
<img
src={src}
// Decorative images use empty string; informative images use descriptive text
alt={decorative ? '' : alt}
/>
)
}
// Usage
<AccessibleImage src="hero.jpg" alt="Team members collaborating in a modern office" />
<AccessibleImage src="divider.png" decorative />
Next.js 版本(next/image 强制要求 alt,装饰图传 ""):
import Image from 'next/image'
// Next.js Image requires alt; use "" for decorative
function HeroBanner() {
return (
<>
{/* Informative */}
<Image
src="/hero.jpg"
alt="Product team celebrating a successful launch"
width={1200}
height={600}
priority
/>
{/* Decorative */}
<Image
src="/wave-divider.svg"
alt=""
width={1200}
height={60}
aria-hidden="true"
/>
</>
)
}
注意装饰图的 alt="" 与 aria-hidden="true" 同时出现——前者处理 <img> 语义,后者进一步抑制辅助树,两者并不冲突而是双保险(对应文档 Verification 一节中"SVG 图标 + 相邻文字标签时用 aria-hidden"的原则在位图场景的延伸)。
Agent 视角:Check / Fix / Explain 三步提示
除了给人读的正文,该规则在 skills/alt-text/SKILL.md 中还以"Agent 可执行的指令"形式存在,包含四段机器可读提示。这是本仓库"规则同时服务人类和 AI Agent"设计的一部分。
Check(检查步骤)——扫描代码库中所有 <img> 元素,逐项验证:
- 每个
<img>都有alt属性(缺失即错误); - 装饰性图片使用
alt=""; - 信息性图片的描述传达图片含义,而非仅文件名;
- 链接图片描述目的地;
- 文字图片在 alt 中复刻文字。
命中以下任一项即应标记:无 alt、alt 与文件名相同(如 alt="photo1.jpg")、泛化值(alt="image" / alt="photo")。
Fix(修复步骤)——对每张问题图片按角色执行:信息性图片描述其传达内容(alt="Bar chart showing 40% increase in sales Q3 2024" 而非 alt="chart");装饰性图片补 alt="";链接图片描述目的地;文字图片逐字复制图中文字;复杂图片用短 alt + aria-describedby 或可见说明。
Explain(解释话术)——面向用户解释 WCAG 2.1 SC 1.1.1 时强调:屏幕阅读器朗读 alt;alt="image" 这类差值等于没有;装饰图必须显式 alt="",因为省略 alt 会导致部分屏幕阅读器朗读文件名。
这四段提示并非手工维护——它们正是源 MDX frontmatter 中 prompts.check / prompts.fix / prompts.explain / prompts.codeReview 字段(见 alt-text.mdx frontmatter)逐字落地的结果。
验证方法:自动化工具 + 手动检查
规则文档将验证拆为两条线。
自动化检查
- axe DevTools / WAVE:两者都会标记"缺失 alt"以及"非装饰性图片使用了空 alt"——注意它们能区分装饰图(空 alt 合法)与信息图(空 alt 违规);
- Lighthouse 可访问性审计:
Images do not have alternate text是计分项(scored item),意味着它会直接影响总分。
这三个工具的名称与链接同时登记在源 MDX 的 tools 字段 中,说明验证手段是规则定义的一部分,而非事后补充。
手动检查
- 启用屏幕阅读器(VoiceOver / NVDA / JAWS),用
G键在图片间导航,逐一确认朗读内容; - 在 Network 面板中任选一个图片 URL,回到 DOM 核对对应
<img>是否有有意义的alt; - CAPTCHA 图片:alt 应描述目的而非字符(如
alt="CAPTCHA: type the characters shown"),并按 WCAG 1.1.1 提供语音替代方案; - 带相邻文字标签的 SVG 图标:图标的含义已被可见文字表达时,对 SVG 使用
aria-hidden="true"而不是 alt。
最后两条是规则文档中最容易被遗漏的边界案例:CAPTCHA 的"字符"本身不应被朗读(也不应被 alt 预先剧透),而"图标 + 文字"组合属于语义冗余,此时 alt 反而是多余的。
仓库中的生成链路:从 MDX 到 skills/alt-text
理解 skills/alt-text/references/rule.md 从何而来,能帮你判断该文档的可信边界:它不是手写副本,而是生成产物。
- 唯一事实源是 packages/content/rules/en/images/alt-text.mdx——frontmatter 承载元数据(priority、tools、resources、prompts、tldr),正文承载上述全部技术内容;
- 生成脚本 scripts/generate/generate-skills.ts 读取该 MDX:
buildSkillMd()(约 L88-L160)把tldr展开为 Quick Reference、把prompts四字段展开为 Check/Fix/Explain/Code Review 小节,产出 SKILL.md;buildReferencesMd()(约 L165-L186)把正文中的 MDX 组件(<Tip>、<CodeTabs>、<Tab>等 JSX)经stripMdxToMarkdown()剥离为纯 Markdown,产出references/rule.md——这解释了你在 rule.md 中看到的 Framework Examples 章节为何有连续空行(Tab 组件被剥离、代码块保留); - 触发方式:根 package.json 中
generate:skills脚本运行tsx scripts/generate/generate-skills.ts,支持全量生成和传入具体.mdx路径的增量模式,后者被 lefthook 在规则 MDX 变更时自动调用(见 scripts/README.md); - 运行时消费:Web 端通过 apps/web/lib/rule-content.ts 的
getRuleRawContent直接从磁盘读取 MDX 正文并剥离 frontmatter(带unstable_cache缓存),供规则详情页与/api/fix-suggestion?slug=alt-text这类接口使用。
由于 references/rule.md 由 MDX 正文转换而来,若发现两者表述差异,以 MDX 源文件为准,并按仓库文档(见 AGENTS.md)通过 pnpm generate:skills 重新生成。
关联规则与标准依据
源 MDX 的 relatedRules 字段声明了三条需要协同审查的规则:
- figure-figcaption:可见说明与 alt 在复杂图片上互补;
- error-images:图片加载失败的降级图同样需要 alt 才能保持可访问;
- dimensions:与 alt 一样作用于图片,常在同一次审查中一并处理。
文档 "Standards" 一节还要求:在认定规则满足之前,实现必须对照 MDN 的 Responsive images 与 web.dev 的 Image performance 两份权威参考核验——这两个 source 亦登记在 frontmatter sources 字段 中。
适用前提:本文所有结论以当前仓库的 alt-text 规则版本为准(priority=critical,Level A 合规项);WCAG 2.1 SC 1.1.1 的判定语义(如"等效文本必须随图片缩放同步可用")以 W3C 原文为最终依据,规则文档未覆盖的边界(如 SVG 内部 <title> 与 alt 的取舍)建议在具体项目中单独核实。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0622
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00