
eslint-plugin-unicorn 的 no-unknown-pseudo-selectors 规则深度解析快照测试揭示的 CSS 伪选择器校验全貌【免费下载链接】eslint-plugin-unicornMore than 300 powerful ESLint rules项目地址: https://gitcode.com/GitHub_Trending/es/eslint-plugin-unicorn导读no-unknown-pseudo-selectors是 eslint-plugin-unicorn 中专门面向 CSS 语言借助eslint/css语言插件的规则用于拦截拼写错误或来历不明的 CSS 伪类pseudo-class与伪元素pseudo-element选择器避免静默失效的样式规则进入代码库。本文以该规则的官方文档 docs/rules/no-unknown-pseudo-selectors.md 为主体结合规则源码 rules/no-unknown-pseudo-selectors.js、标准选择器清单 rules/shared/standard-pseudo-selectors.js 以及 AVA 快照测试报告 test/snapshots/no-unknown-pseudo-selectors.js.md 中的 16 个 invalid 用例系统讲解该规则的判定逻辑、边界行为、allow配置项以及它在 ESLint 多语言配置中的接入方式。规则背景为何需要校验伪选择器CSS 中伪类与伪元素的名字一旦拼错浏览器并不会报错而是直接把整条选择器判定为永不匹配——这是典型的静默失败代码不崩、构建不报错但样式悄悄失效。例如/* ❌ 拼写错误选择器永不匹配 */ :foucs {} ::befor {} /* ✅ 正确写法 */ :focus {} ::before {}该规则的核心职责正是对 CSS 文件中的伪类、伪元素名称与种类单冒号还是双冒号进行校验其判定基准来自 CSS 规范包含 Editors Drafts 草案阶段的选择器由webref/css包提供标准列表并补充少量缺失定义。规则元数据中type: problemrules/no-unknown-pseudo-selectors.js并在meta.languages中声明css/css意味着它仅在以 CSS 为语言的 ESLint 配置段内生效不会误伤 JavaScript 文件。快照测试整体概览AVA 快照文件 test/snapshots/no-unknown-pseudo-selectors.js.md 记录了规则在 16 个 invalid 用例上的完整输入与错误输出而对应的测试用例定义在 test/no-unknown-pseudo-selectors.js。快照中每条错误的格式为 1 | :foucs {} | ^^^^^^ Unknown pseudo-selector :foucs.^精确标出问题选择器在源码中的位置错误消息统一为Unknown pseudo-selector {{selector}}对应源码中的messages定义。这 16 个用例恰好覆盖了该规则绝大部分判定边界下面按行为类别逐一拆解。行为一简单拼写错误与单条规则内的多错误报告最基本的场景是单个选择器拼写错误:foucs {} /* 报错Unknown pseudo-selector :foucs */当一条规则里同时存在多个错误时规则会逐一报告而不是只报第一个。快照 invalid(2) 演示了这一点:hovr::befor {}该用例同时产生两条错误:hovr伪类错误与::befor伪元素错误且^标记分别精确覆盖各自对应的源码区间。从实现看rules/no-unknown-pseudo-selectors.js 通过context.on(PseudoClassSelector, ...)与context.on(PseudoElementSelector, ...)两个监听器分别处理伪类与伪元素节点每个节点独立判定、独立报告因此同一条规则内的多个问题会被完整暴露。行为二嵌套选择器上下文中的递归校验现代 CSS 的:is()、:not()、:has()、:nth-child(2n of ...)等函数式伪类可以在参数中携带完整的复杂选择器。快照 invalid(3) 与 invalid(4) 证明规则会深入这些嵌套上下文:is(.foo:foucs, :not(.bar:hovr)) {} /* 报 2 个错误 */ :has( .foo:foucs), :nth-child(2n of :hovr), ::slotted(.bar:foucs) {} /* 报 3 个错误 */文档中对此有明确边界说明规则不校验选择器的上下文与参数本身的语义嵌套的伪选择器仅在eslint/css将参数解析为选择器时才会被检查见 docs/rules/no-unknown-pseudo-selectors.md。也就是说能查多深取决于 CSS 解析器对参数结构的识别程度这是规则依赖底层语言插件的一个已知边界。行为三CSS 嵌套写法与 规则内的选择器除了普通选择器规则同样覆盖 CSS 嵌套CSS Nesting语法与条件性 规则。快照 invalid(5) 与 invalid(6).foo { :hovr {} } /* 嵌套选择器报 1 个错误 */ supports selector(:foucs) {} scope (:hovr) to (:foucs) {} /* 报 3 个错误 */其中supports selector(...)与scope (...) to (...)都携带选择器参数规则均能定位并报告其中的未知伪选择器。这说明规则的检查不局限于样式块顶层的选择器列表而是作用于整个 CSS AST 中出现PseudoClassSelector/PseudoElementSelector节点的所有位置。行为四伪类与伪元素是两套独立的命名空间这是该规则最重要的设计之一伪类与伪元素的名字互不通用。快照 invalid(7) 与 invalid(8) 用两个看似正确的用例验证了这一点::hover {} /* 报错尽管 :hover 是标准伪类但 ::hover 不是标准伪元素 */ :backdrop {} /* 报错尽管 ::backdrop 是标准伪元素但 :backdrop 不是标准伪类 */伪元素的标准写法是双冒号部分历史伪元素如:before、:after、:first-line、:first-letter同时存在于单冒号与双冒号两个标准清单中见 rules/shared/standard-pseudo-selectors.js而::hover、:backdrop这种跨命名空间的写法会被判定为未知。这也是官方文档中明确强调的判定规则。行为五厂商前缀与框架专属选择器默认全部报错快照 invalid(9) 至 invalid(12) 展示了几类非标准但常见的选择器它们默认全部被标记为未知:-webkit-autofill {} /* WebKit 前缀伪类 */ ::-webkit-slider-thumb {} /* WebKit 前缀伪元素 */ :global(.foo) {} /* CSS Modules 等框架语法 */ ::theme-part(.foo) {} /* 框架自定义伪元素 */原因在于标准清单仅收录 CSS 规范定义的名称rules/shared/standard-pseudo-selectors.js 中可看到标准列表全部来自规范定义并无任何-webkit-前缀条目。官方文档明确要求厂商前缀与框架特定的选择器必须通过allow选项显式放行。这也解释了测试文件中 valid 用例为何需要options: [{allow: [:global, :deep, ::theme-part]}]才能通过。行为六自定义选择器:--custom自动放行::--custom不行CSS 自定义选择器Custom Selector以--开头形如:--heading。规则对其有专门的豁免逻辑:--custom, :--custom(value) {} /* ✅ 自动允许无需配置 */ ::--custom {} /* ❌ 报错Unknown pseudo-selector ::--custom */快照 invalid(13) 表明::--custom双冒号形式仍会被报告。对应源码 rules/no-unknown-pseudo-selectors.js 中isCustomSelector只对PseudoClassSelector类型且解码后以--开头的节点放行PseudoElementSelector不享受该豁免。行为七CSS 转义序列与 Unicode 近似字符CSS 允许用反斜杠转义表示字符例如:\3A backdrop中的\3A就是十六进制转义后的冒号。快照 invalid(14) 显示该写法会被正确识别为伪选择器:\3A backdrop并报告为未知。反过来测试文件中的 valid 用例:\3A theme配合allow: [:\\3A theme]又能通过——说明allow选项支持转义形式判定前两者都经过统一的解码处理。更隐蔽的陷阱是 Unicode 近似字符。快照 invalid(15) 使用了:linK末尾的KU212A开尔文符号在视觉上与字母K几乎无法区分但它不是 ASCII 的K因此:link的标准匹配不生效被报告为未知伪选择器。这类用例提醒开发者肉眼看似正确的选择器也可能因为不可见字符差异而失效。行为八allow选项严格区分单冒号与双冒号allow用于放行非标准选择器但其匹配不是只要名字对就行。快照 invalid(16) 演示了关键边界/* 配置 allow: [:foo] */ ::foo {} /* ❌ 仍报错Unknown pseudo-selector ::foo */尽管名字都是foo但:foo是伪类、::foo是伪元素种类不同allow中的单冒号条目不会放行双冒号形式。官方文档对此的表述是每个条目必须包含一个或两个前导冒号以标识其种类。allow配置项完整说明根据 docs/rules/no-unknown-pseudo-selectors.md 与源码 schemarules/no-unknown-pseudo-selectors.js类型string[]默认值[]匹配规则ASCII 大小写不敏感测试中:HOVER, ::BEFORE {}配合放行能通过同时覆盖函数式与非函数式两种形态即:global一条可同时放行:global与:global(.foo)。条目合法性schema 中allow条目的 pattern 为^:{1,2}(?:\\.|[^\\:()])$即必须以一或两个冒号开头不能包含未转义的冒号与括号。转义支持条目支持 CSS 转义写法如String.raw:\3A theme、String.raw:\\66 oo后者可放行:foo。典型配置示例{ allow: [ :global, :deep, ::-webkit-slider-thumb, ], }源码实现原理标准化判定键规则的核心判定逻辑值得展开。在 rules/no-unknown-pseudo-selectors.js 中每个伪选择器都会被转换为一个标准化键再参与比较const toAsciiLowerCase string string.replaceAll(/[A-Z]/g, c c.toLowerCase()); const getPseudoSelectorKey pseudoSelector { const colonCount pseudoSelector.startsWith(::) ? 2 : 1; return ${colonCount}:${toAsciiLowerCase(ident.decode(pseudoSelector.slice(colonCount)))}; };关键步骤有三确定种类根据是否以::开头把冒号数量1 或 2作为键的前缀实现伪类与伪元素命名空间隔离解码转义ident.decode把 CSS 转义序列还原为真实字符这正是\3A、\66等转义写法能与普通写法互相匹配的原因ASCII 小写化对[A-Z]做小写归一化实现大小写不敏感匹配——注意这里只处理 ASCII 字符所以KU212A这类非 ASCII 字符不会被归一化从而被正确判为未知。随后规则将标准清单standardPseudoSelectors与allow配置各自映射为标准键集合对 AST 中的每个伪类/伪元素节点做集合查找不在两个集合中即报告错误rules/no-unknown-pseudo-selectors.js。标准选择器清单从何而来规则所依据的标准清单位于 rules/shared/standard-pseudo-selectors.js文件头注释标明它是生成文件禁止手工编辑。生成脚本是 scripts/create-css-pseudo-selectors.js从webref/css包拉取全部选择器定义过滤出以:开头的名称并去掉函数式伪类名称末尾的()因此清单中只有:nth-child而没有:nth-child()补充 Webref 缺失的:recto、:verso、::prefix、::suffix四个规范条目结果按字典序排序后写入生成文件--check模式下会校验文件是否过期过期则提示运行npm run fix:css-pseudo-selectors重新生成。这意味着标准清单会随webref/css的更新而演进新进入 CSS 草案的选择器在重新生成后即可被识别这也是规则能覆盖Editors Drafts级别选择器的机制来源。当前清单共收录 156 条标准选择器涵盖:focus、:hover、:is()、:has()、:nth-child()等常用伪类以及::before、::after、::backdrop、::selection、::view-transition-*等伪元素rules/shared/standard-pseudo-selectors.js。在 ESLint 配置中启用该规则该规则在 configs 推荐配置 中默认关闭推荐配置与 unopinionated 配置均未包含需要显式开启。同时它只适用于 CSS 语言必须在配置了eslint/css语言插件的 CSS 配置段内启用。参照 readme.md 中非 JavaScript 文件的接入示例import css from eslint/css; import unicorn from eslint-plugin-unicorn; import {defineConfig} from eslint/config; export default defineConfig([ { files: [**/*.css], plugins: { css, unicorn, }, language: css/css, rules: { unicorn/no-unknown-pseudo-selectors: error, // 若项目使用 CSS Modules、Vue scoped 等语法可配合放行 // unicorn/no-unknown-pseudo-selectors: [error, {allow: [:global, :deep]}], }, }, ]);小结通过快照测试报告 test/snapshots/no-unknown-pseudo-selectors.js.md 中的 16 个用例可以完整还原no-unknown-pseudo-selectors的判定行为它覆盖普通选择器、函数式伪类嵌套、CSS 嵌套与 规则上下文严格区分伪类/伪元素两套命名空间默认拒绝厂商前缀与框架语法对自定义选择器:--形式自动放行支持 CSS 转义与 ASCII 大小写归一化并且allow配置按冒号种类精确匹配。结合 rules/no-unknown-pseudo-selectors.js 的实现与 scripts/create-css-pseudo-selectors.js 的生成机制开发者可以清楚预判规则在各类写法上的行为从而在 CSS 工程中既保留合法写法又彻底消灭永不匹配的静默失效选择器。【免费下载链接】eslint-plugin-unicornMore than 300 powerful ESLint rules项目地址: https://gitcode.com/GitHub_Trending/es/eslint-plugin-unicorn创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考