w3c validator不报lang属性问题,因其仅校验html语法合法性,不验证lang值是否符合bcp 47规范、位置是否正确或语义是否有效,故会放过lang="chinese"等错误写法。

W3C Validator 为什么报不了 lang 属性问题
W3C Markup Validation Service(https://validator.w3.org/nu/)只检查 HTML 语法合法性,不校验 lang 属性值是否符合 BCP 47 规范,也不检查它是否写在正确位置。它可能放过 lang="chinese"、lang="zh-CN-zh" 或 这类严重错误——因为这些“语法上合法”,只是语义和标准上无效。
常见误判场景包括:
-
lang="zh"被验证器接受,但实际无法触发 Chrome 翻译按钮或 NVDA 正确朗读 -
<div lang="en">Hello 欢迎</div>不报错,但浏览器不会对“欢迎”做拼写检查(也没词典) -
大小写混用,验证器不拦,但部分 SSR 框架或 i18n 工具会解析失败
怎么真正验证 lang 属性是否合规
必须分三步:位置、值、层级。缺一不可。
实操建议:
- 位置:只检查
标签是否含lang属性,其他位置(、<div>)写的都算冗余或干扰项 <li>值:用正则匹配是否符合 BCP 47 基础格式,例如 <code>/^[a-z]{2,3}(-[A-Z][a-z]{3})?(-[A-Z]{2}|-[0-9]{3})?$/;拒绝zh(太宽泛)、Chinese(非标准)、zh-CN-zh(重复子标签) - 层级:若页面含外语片段(如英文引文、代码注释),需在对应元素显式覆盖,例如
<blockquote lang="en"></blockquote>;但前提是根节点已存在 - 用
html-validate配置规则:"attr-req-lang": true(强制根节点有lang)、"attr-valid-lang": true(校验值格式) - Shell 脚本快速抽检:
grep -oP ']*lang="\K[^"]+' dist/index.html | head -1 | grep -E '^[a-z]{2,3}(-[A-Z][a-z]{3})?(-[A-Z]{2}|-[0-9]{3})?$' - Playwright 脚本断言:
await page.evaluate(() => document.documentElement.lang === 'zh-CN'),适合 SSR 页面构建后验证 -
<meta charset="utf-8">是否位于最前面?若它被<title></title>或注释挡住,浏览器可能用 ISO-8859-1 解析前几个字节,导致lang值被截断或乱码 - 是否同时存在
<meta http-equiv="Content-Language">?该标签已废弃,且会干扰部分旧版爬虫对lang的识别 - 是否用了
dir="rtl"却没配对应语言?例如lang="ar"必须搭配dir="rtl",否则 CSS 逻辑属性(如margin-inline-start)行为异常 - 服务端返回的 HTTP
Content-Type头是否含charset=utf-8?若响应头声明charset=iso-8859-1,会直接覆盖 HTML 内的meta声明
CI 中自动化检测 lang 的可行方式
靠人工肉眼检查不可持续,工程化交付必须进 CI 流水线。
推荐组合:
注意:Vite / Next.js 等框架若在 JS 中动态设置 document.documentElement.lang,静态扫描会漏检,必须走端到端运行时校验。
lang 属性被忽略的典型现象与排查点
即使写了 lang="zh-CN",也可能被浏览器或辅助技术无视。最常踩的坑不是“没写”,而是“写了但失效”。
关键排查项:
真正起效的 lang,是位置、值、编码、响应头四者咬合的结果。少一个,就可能让翻译、朗读、SEO 全部掉链子。











