htmllint默认配置误报主因是未区分静态HTML与模板语法场景,如Vue的v-if、Handlebars的class="{{}}"被误判,因其仅按.html后缀严格解析,不识别文件类型上下文。

为什么htmllint默认配置会误报
htmllint 默认启用的规则里,attr-name、attr-value-not-empty 和 id-class-value 这几条对模板引擎或 SSR 场景极不友好。比如 Vue 模板中 v-if="show" 会被当成非法属性名报错;class="{{className}}"(旧版 Handlebars)也会触发 attr-value-not-empty。这不是 bug,而是规则没区分「纯静态 HTML」和「带模板语法的 HTML」。
真正影响准确性的关键不是规则多不多,而是是否显式声明解析上下文。htmllint 不像 ESLint 那样自动识别 .vue 或 .njk 文件类型,它只认 .html 后缀,且默认按严格 HTML5 解析。
- 必须在
.htmllintrc中用doctype显式指定"html5"或"none"(后者禁用 DOCTYPE 校验,适合模板文件) - 对含插值语法的文件,加
"attr-bans": ["v-", "ng-", "data-"]临时绕过属性名检查,比全局关规则更安全 - 避免使用
"tag-req-attr"检查自定义元素(如<my-button>),它只认标准 HTML 元素列表
如何让规则适配不同 HTML 类型
一个项目常混用多种 HTML:纯静态页、Vue 单文件组件里的 <template>、Nunjucks 模板、甚至 Markdown 中的内联 HTML。统一用一套规则必然误报或漏报。
htmllint 本身不支持 per-file-type 配置,但可通过构建层隔离:用 htmllint-cli 分批调用,每类文件传不同配置文件。
立即学习“前端免费学习笔记(深入)”;
- 静态页走
htmllint --config .htmllintrc.static src/pages/**/*.html - Vue 模板走
htmllint --config .htmllintrc.vue src/**/*.vue,其中关闭attr-name、开启attr-req-quotes(防v-bind:href=xxx缺引号) - Nunjucks 模板配置里加
"attr-bans": ["{{", "{%"],避免把模板变量当属性值误判
注意:不要试图用 ignore 字段跳过整个文件——这等于放弃检查,而应针对性关单条规则。
哪些规则必须保留才能守住底线
零误报 ≠ 零规则。真正该坚持的只有三条:能拦截 80% 渲染异常的硬性约束。
-
attr-quote-style:强制双引号,避免href='javascript:void(0)'在某些解析器中被截断 -
head-script-disabled:禁止<script>写在<head>里(除非标记type="module"),这是现代浏览器执行顺序的雷区 -
img-req-alt:强制alt属性,不只是可访问性要求,更是防止图片加载失败时布局塌陷的保险丝
其他如 indent-style、max-attr-length 属于风格层,关掉也不会导致运行时错误;而 id-class-ad-disabled(禁用广告类 class 名)这类业务规则,应交给 CI 阶段的自定义脚本,别塞进 htmllint。
CI 流程里怎么避免“修复即引入新误报”
团队每次升级 htmllint 版本或改规则,都可能让原本通过的 PR 突然失败。这不是配置问题,是规则语义变更没被感知。
最稳妥的做法是:把当前通过的检查结果快照存为 baseline,后续只允许新增错误,不允许旧错误消失或变化。
- 首次运行
htmllint --json > htmllint.baseline.json,提交该文件到仓库 - CI 脚本中先跑
htmllint --json > htmllint.current.json,再用jq对比两个 JSON 的errorCount和warningCount是否只增不减 - 若 baseline 里某行报
attr-value-double-quotes错误,而新版不再报——说明规则被弱化,需人工确认是否合理
这条防线容易被忽略:htmllint 更新日志从不标注某条规则的匹配逻辑是否变更,只能靠 baseline 做事实锚点。



















