Front Matter 必须显式声明 lang 和 dir 字段,模板中渲染为 <html lang="{{ page.lang }}" dir="{{ page.dir }}">;导航用 <nav>、主内容用 <main>、标题严格嵌套、图片 alt 不可空、链接文字需自解释。

Front Matter 里必须声明 lang 和 dir 字段
可访问性不是靠 CSS 或 JS 补救的,而是从 <html> 根标签开始。Eleventy、Hugo 等工具默认不注入 lang 或 dir 属性,但屏幕阅读器依赖它们判断语言切换和文本流向。
正确做法是在每个内容文件的 Front Matter 中显式声明:
-
lang: zh-CN(不要写成language: zh,模板里取值必须匹配字段名) -
dir: ltr或dir: rtl,中文/英文用ltr,阿拉伯语等用rtl - 在模板中渲染为:
<html lang="{{ page.lang }}" dir="{{ page.dir }}"> - 若全站统一,可在全局数据(如
_data/site.json)里定义,再通过{{ site.lang }}注入,避免每篇重复写
模板中必须用语义化 HTML 标签,且禁用纯 div 导航
静态生成器不校验 HTML 语义,<div class="nav"> 在构建后仍是 <div>,对屏幕阅读器不可见。你得手动写对标签,并确保它被原样输出。
常见错误与修正:
立即学习“前端免费学习笔记(深入)”;
- 导航栏必须用
<nav>包裹,内部用<ul><li><a>,别用<div><span><button> - 主内容区必须用
<main>,且全站只能有一个(Eleventy 模板里别在循环中重复写<main>) - 文章标题必须用
<h1>到<h6>严格嵌套,不能靠 CSS 把<div class="h1">伪装成标题 - Hugo 的
{{ .Content }}或 Eleventy 的{{ content | safe }}输出 Markdown 渲染结果,要确认渲染器生成的是语义化 HTML(比如## 标题→<h2>,不是<p><strong>)
图片 alt 属性不能留空,且需在模板中强制校验
Markdown 写  是基础,但实际中常出现 (空 alt)或 (无意义 alt),这类问题构建时不会报错,却直接导致 WCAG 2.1 失败。
解决方案分两层:
- 在模板中用条件逻辑兜底:
{% if img.alt %}alt="{{ img.alt }}"{% else %}alt=""{% endif %}—— 空字符串允许跳过,但绝不能省略属性本身 - 构建前加简单检查脚本(如用 Node.js +
glob扫描所有.md文件):匹配!\[\]\(或![^]]*\]\(但不含文字的行,自动告警 - Eleventy 可在
.eleventy.js中用addTransform针对 HTML 输出做二次处理,把缺失alt的<img>自动补alt="",但注意别覆盖已有有效值
链接文字必须可独立理解,避免“点击这里”类文案
静态站点没有运行时分析能力,无法像 Lighthouse 那样动态检测链接上下文。所有链接文本必须自带含义,否则视障用户用阅读器跳链时会听到孤立的“点击此处”“了解更多”,完全不知所指。
实操要点:
- 禁止在 Markdown 或模板中写
[点击这里](/about);改用[关于我们的团队](/about)或[查看产品文档](/docs) - 若设计稿强制用“了解更多”,至少加
aria-label:<a href="/blog" aria-label="阅读最新技术博客">了解更多</a> - Eleventy 的
addShortcode可封装安全链接组件,强制要求传入text和ariaLabel参数,避免漏写 - 注意 Hugo 的
{{ relLangURL }}或 Eleventy 的{{ url | url }}过滤器只处理路径,不碰链接文本——可访问性责任始终在内容作者端
最易被忽略的一点:键盘焦点管理不在生成阶段解决,而在于你是否在模板中主动写 tabindex="-1" 或 aria-hidden="true"。静态生成器只管输出 HTML,它不会帮你判断某个装饰性图标该不该被聚焦。这意味着可访问性不是配置开关,而是每一处 <div>、每一个 alt、每一行 Markdown 链接的持续选择。



















