必须启用tag-pair规则,因浏览器自动修复未闭合标签仅保证显示,不保证语义正确;该规则强制校验开闭匹配,防止DOM结构错误,但对JS模板字符串、构建注入内容等场景需额外配置或配合其他工具校验。
tag-pair 规则必须启用,且不能只靠浏览器渲染判断浏览器会自动修复未闭合标签,比如把 <p>内容</p><div>嵌套</div>
<p>内容</p><div>嵌套</div>,但语义已错。校验器报 Element div is not allowed here 不是警告,是结构非法。真正要卡住的不是“能不能显示”,而是“是否被解析为预期 DOM”。tag-pair 规则强制检查开闭匹配,包括自闭合标签(如 <img alt="前端自动化校验:将标签配对与语义规范纳入HTML代码质量核验" > 在 HTML5 中可不写斜杠,但 <br>必须一致)。
innerHTML = `<div>${text}</div>`),htmlhint 默认不扫描 JS 文件,需额外配置 htmlvalidate 或预处理提取v-html 或 dangerouslySetInnerHTML 注入的内容,必须单独提取校验,否则规则完全失效index.html 中注入的注释或变量(<!-- built at ... -->),会干扰 tag-pair 判断,需在 CI 前清理模板htmlhint 的语义规则怎么配才不形同虚设默认 .htmlhintrc 里只开了基础语法项,id-unique、attr-lowercase 这类属于格式规范,对语义无约束。真要卡语义,得手动加这几条:
doctype-first:确保 <!DOCTYPE html> 在第一行,否则整个文档进 Quirks Mode,后续所有语义检查失去意义head-title-require:强制 <head> 内有且仅有一个 <title>,避免 SEO 失效attr-no-duplication:防止 <div id="header" id="nav"> 这种冲突属性,影响 JS 选择器稳定性element-permitted-content:启用后会报 <p><section></section></p> 这类嵌套违规,但性能略降,建议只在 CI 阶段开启注意:htmlhint 不校验 ARIA 属性合法性(如 aria-role="button" 拼错),这类需搭配 axe-core 或 html-validate 的 valid-aria 规则。
立即学习“前端免费学习笔记(深入)”;
htmlhint 容易漏掉的三个执行细节本地 npx htmlhint src/*.html 能过,CI 却失败,大概率栽在这三处:
run: npx htmlhint **/*.html 在 shell 里可能被提前展开,应写成 npx htmlhint "**/*.html" 或改用 find + xargs
ignore 是相对路径,CI 环境工作目录常为 /github/workspace,需写全路径或用 glob 模式(dist/**/*.html)htmlhint 读取时首行变成 <!DOCTYPE html>,直接触发 doctype-first 报错,CI 前加一步 sed -i '1s/^xEFxBBxBF//' *.html
htmlhint
htmlhint 只分析静态 HTML 字符串,对 v-if、ngIf、JSX 条件渲染等内容完全不可见。比如一个 <header v-if="showHeader">,若 showHeader 为 false,最终 DOM 根本没有 <header>,但 htmlhint 仍会检查它是否符合语义——这毫无意义。
真实校验链路得补两环:
dist/index.html,再用 page.content() 获取实际渲染后的 HTML 字符串,喂给 html-validate
axe.run(),捕获 region-no-label、heading-order 等动态语义问题,结果上报到日志系统.vue 文件,用 eslint-plugin-vue 的 vue/valid-template-root 和 vue/html-closing-bracket-newline 规则,在源码阶段拦截问题语义规范不是写完就结束的事,它横跨模板、构建、渲染三层。漏掉任何一层,校验都只是纸面合规。