eslint-plugin-unicorn 的 no-duplicate-css-selectors 规则:检测并修复重复 CSS 选择器
eslint-plugin-unicorn 的 no-duplicate-css-selectors 规则检测并修复重复 CSS 选择器【免费下载链接】eslint-plugin-unicornMore than 300 powerful ESLint rules项目地址: https://gitcode.com/GitHub_Trending/es/eslint-plugin-unicorn本篇技术指南围绕 eslint-plugin-unicorn 中面向 CSS 语言的核心规则no-duplicate-css-selectors展开讲解它如何发现样式表中的重复选择器与重复选择器列表、其上下文比较机制at-rule、嵌套、层叠上下文、自动修复能力以及与css/no-duplicate-keyframe-selectors的分工。读完本文你将掌握该规则的完整配置方式、检测边界与修复行为并能从源码与测试层面理解其实现原理直接应用于自己的 CSS 工程。规则概览与启用状态no-duplicate-css-selectors用于禁止重复的 CSS 选择器其官方说明见 docs/rules/no-duplicate-css-selectors.md。该规则的几个关键属性如下属性值规则类型meta.typeproblem是否可自动修复是fixable: code配合--fix使用是否带配置选项否schema: []适用语言CSSmeta.languages: [css/css]在recommended配置中关闭在unopinionated配置中关闭从源码 rules/no-duplicate-css-selectors.js 可以看到规则的meta.docs.recommended为false因此它不会随官方推荐配置自动开启需要在项目配置中按需显式启用。同时meta.languages声明为css/css说明这是一条非 JavaScript 语言规则必须与 ESLint 的 CSS 语言插件配合使用。为什么需要检测重复选择器样式表中的重复选择器块其来源通常是合并merge冲突多人协作或分支合并时同一段样式被同时添加复制粘贴从其他文件复制规则块后忘记删除原文不完整的重构拆分或抽取组件时旧选择器未被清理。重复选择器的危害不止于代码冗余它们会把本应集中在一起的声明拆分到样式表的不同位置而 CSS 的层叠规则决定了后出现的声明会意外覆盖先出现的声明在优先级相同时。例如下面这段代码中.card被声明了两次color: blue会覆盖前面的color: red/* ❌ 违反规则 */ .card { color: red; } .card { color: blue; }这类幽灵覆盖极难排查因为两处声明看似独立、都合法实际却在运行时互相打架。该规则的价值正是把这种隐患在 lint 阶段直接暴露出来。规则检测的两种重复模式该规则并非只做简单的同名选择器去重而是区分两种重复场景并给出不同的报错信息对应源码中的两个messageId见 rules/no-duplicate-css-selectors.jsmessageId报错文案触发场景duplicate-selectorThis selector duplicates the selector on line {{line}}.同一选择器列表内存在重复的单个选择器duplicate-selector-listThis selector list duplicates the selector list on line {{line}}.同一上下文at-rule / 嵌套 / 层叠上下文中出现重复的完整选择器列表模式一选择器列表内的重复选择器同一个选择器列表中一个选择器被写了两次/* ❌ 违反规则 */ .button, .button { padding: 8px; }报错信息会提示与首次出现位置的行号便于定位。模式二跨规则块的重复选择器列表分别位于两个规则块中的完全相同的选择器列表会被视为重复/* ❌ 违反规则 */ .card { color: red; } .card { color: blue; }这里的判定不是选择器名字符串相等而是比较序列化后的完整选择器列表源码中使用eslint/css-tree的generate()对rule.prelude进行规范化输出见 rules/no-duplicate-css-selectors.js。因此选择器内部的无关紧要空白差异会被忽略——下面两种写法会被判定为重复/* ❌ 违反规则 */ media (width 10px) { .card { color: red; } } media(width10px) { .card { color: blue; } }从测试用例 test/no-duplicate-css-selectors.js 可以看到media (width 10px)与media(width10px)是 invalid 用例证实了空白不敏感的比较行为。同理a b与a/* comment */b也会被判定为重复test/no-duplicate-css-selectors.js印证文档所述比较时忽略无关紧要的选择器空白和注释。上下文比较机制只在同一环境下判定重复这是本规则最核心的设计重复判定是上下文敏感的。两个规则块必须处于相同的 at-rule 与嵌套上下文中才会互相构成重复。匹配的条件上下文会被比较即使两个条件块是分开书写的只要条件相同其中的选择器仍会被互相比较/* ❌ 违反规则两个 media 条件一致.card 重复 */ media (width 40rem) { .card { color: red; } } media (width 40rem) { .card { color: blue; } }这里规则会把media (width 40rem)作为上下文键的一部分两个块共享同一上下文因此内部的.card被判定为重复。不同的上下文则被允许只要条件不同重复就不成立/* ✅ 符合规则断点条件不同属于不同上下文 */ media (width 40rem) { .card { color: red; } } media (width 60rem) { .card { color: blue; } }类似的比较也适用于其他 at-rule。测试用例覆盖了supports、container、scope以及命名layer的同类场景——例如supports (display: grid)与supports(display:grid)是 invalid而不同条件之间是 valid见 test/no-duplicate-css-selectors.js。嵌套上下文同样参与判定CSS 嵌套nesting形成的层级也是上下文的一部分。同一个父选择器下的重复嵌套子规则会被报告/* ❌ 违反规则 */ .component { .title { color: red; } } .component { .title { color: blue; } }而不同父容器下的同名子选择器是合法的/* ✅ 符合规则 */ .parent { .child { color: red; } } .other-parent { .child { color: blue; } }上述用例分别出现在 test/no-duplicate-css-selectors.js 与 test/no-duplicate-css-selectors.js。匿名 layer 的特殊处理匿名layer即不带名称的layer { ... }在源码中会被特殊处理getContextPart对无 prelude 的layer返回[anonymous-layer, 起始位置]用源码位置作为上下文标识rules/no-duplicate-css-selectors.js。因此不同位置的两个匿名 layer 中的同名选择器不会互相构成重复/* ✅ 符合规则两个匿名 layer 被视为不同上下文 */ layer { .card { color: red; } } layer { .card { color: blue; } }而命名layer如layer components因为名称相同会被视为同一上下文其中的重复选择器会被报告见 test/no-duplicate-css-selectors.js。不会被报告的情况规则的边界规则明确不报告以下几类看似相似但并非重复的选择器保证误报率可控1. 部分重叠的选择器列表/* ✅ 符合规则 */ .card, .featured {} .card {}它比较的是完整的选择器列表按原始顺序不会把[.card, .featured]与[.card]视为重复。2. 重排后的选择器列表/* ✅ 符合规则 */ .card, .featured {} .featured, .card {}列表顺序不同即视为不同列表[.card, .featured]与[.featured, .card]不会被互相判定为重复。3. 仅在选择器解析后才等价的情况嵌套/* ✅ 符合规则 */ .parent .child {} .parent { .child {} }generate()比较的是语法层面的原始选择器不会在解析 CSS 嵌套语义即把 .child展开为.parent .child之后再进行比较。因此.parent .child与嵌套写法 .child不会被判定为重复。4. 大小写不同、转义形式不同从测试用例可见.Card与.card是 validtest/no-duplicate-css-selectors.js.u-m\2b与.u-m\00002b也是 validtest/no-duplicate-css-selectors.js——即比较对大小写敏感且不同转义写法视为不同选择器。5. 关键帧keyframes选择器keyframes内部的from/to/ 百分比选择器会被整体跳过见下文专门说明。关键帧选择器交给专属规则处理规则对关键帧做了明确的职责划分。源码中通过正则keyframesNamePattern /^(?:-(?:o|moz|webkit)-)?keyframes$/iu识别keyframes及其带浏览器前缀的变体-o-keyframes、-moz-keyframes、-webkit-keyframes一旦某个 at-rule 匹配该模式getContextKey会直接返回undefined整个子树被跳过rules/no-duplicate-css-selectors.js。因此下面的代码不会触发本规则/* ✅ 本规则不检查 keyframes */ keyframes fade { from { opacity: 0; } from { opacity: 1; } }对应测试用例见 test/no-duplicate-css-selectors.js。文档明确建议关键帧选择器应交给css/no-duplicate-keyframe-selectors检查形成两条规则各司其职的组合方案。配置方法在 flat config 中启用由于该规则面向 CSS 语言需要与eslint/css中关于非 JavaScript 语言规则的配置指引完整示例如下import css from eslint/css; import unicorn from eslint-plugin-unicorn; import {defineConfig} from eslint/config; export default defineConfig([ { files: [**/*.js], plugins: { unicorn, }, extends: [ unicorn/recommended, ], }, { files: [**/*.css], plugins: { css, unicorn, }, language: css/css, rules: { unicorn/no-duplicate-css-selectors: error, }, }, ]);要点必须用files限定 CSS 文件并将 Unicorn 的 JavaScript 规则与 CSS 规则分置于不同配置对象避免把 JS 规则错误作用到 CSS 文件上language: css/css指定使用eslint/css语言插件该规则没有配置选项schema: []直接开启error或warn即可无需也不支持传参规则已注册在插件入口 rules/index.js 中启用后即可直接以unicorn/no-duplicate-css-selectors引用。自动修复与修复边界该规则支持--fix自动修复meta.fixable: code这是它的一大实用特性。修复逻辑在源码 rules/no-duplicate-css-selectors.js 中对于同一选择器列表内的重复选择器规则会计算并移除重复项保留首次出现项修复是保守的只有当重复选择器与前一选择器之间的分隔符是纯空白逗号匹配/^\s*,\s*$/u且该区间内不存在注释时才会生成移除修复getDuplicateSelectorRemovalRange返回undefined表示不修复修复通过重写整个rule.prelude选择器列表完成按从后往前的顺序逐个剪掉重复区间避免位置偏移问题。测试用例 test/no-duplicate-css-selectors.js 给出了修复的精确输出// 输入a, b, a, b { color: red; } → 输出a, b { color: red; }报 2 个错误 // 输入a /* keep */, b, a { color: red; } → 输出a /* keep */, b { color: red; }报 1 个错误 // 输入a, /* keep */ a, b, b { color: red; } → 输出a, /* keep */ a, b { color: red; }报 2 个错误可以看到凡是重复选择器紧邻注释的场景修复会保留注释所在的选择器项绝不贸然删除可能承载信息的代码。而跨规则块的重复选择器列表模式二只报告、不修复——因为删除哪个块属于无法自动决策的重构问题需要人工判断。源码实现剖析规则实现位于 rules/no-duplicate-css-selectors.js核心是create函数第 91-154 行整体流程如下监听Rule节点对每个规则先确认其prelude是SelectorList类型第 96-98 行计算上下文键getContextKey沿父节点链向上遍历收集所有Atrule与Rule节点用getContextPart生成各自的上下文片段at-rule 记录名称与 prelude、普通规则记录 prelude、匿名 layer 记录位置最终以 JSON 字符串作为上下文键第 54-86 行。这正是相同 at-rule 嵌套上下文才判定重复的机制来源检测列表内重复对当前SelectorList的每个子选择器用generate()序列化后存入seenSelectorsMap命中即为列表内重复第 109-133 行检测跨块重复列表以上下文键 → 选择器列表键的两级 Map 记录历史selectorListsByContext按上下文隔离记录同一上下文内出现相同generate(rule.prelude)即报告duplicate-selector-list第 135-152 行。值得注意的两点实现细节报告信息带行号报错数据中的line取自首次出现节点firstSelector/firstSelectorList的起始行方便快速定位原件上下文键使用序列化字符串at-rule 的条件部分prelude也经过generate()规范化因此media (width 10px)与media(width10px)会产生相同上下文键——这也解释了测试中这类用例被判为重复的原因。测试覆盖情况规则的测试文件为 test/no-duplicate-css-selectors.js通过getTester与 CSS 语言配置languages.css见 test/utils/languages.js运行并配合快照test/snapshots/no-duplicate-css-selectors.js.md与显式修复断言。覆盖维度包括不同选择器、部分重叠、重排列表均为valid大小写不同、转义形式不同的选择器为valid不同断点 / 不同父容器 / 匿名 layer / keyframes 内重复为valid同断点不同空白写法、同层命名 layer、同父嵌套子规则重复为invalid修复输出与错误数量的精确断言。快照中还可见该规则的报错形态例如.card { color: red; } .other { color: green; } .card { color: blue; }会报告This selector list duplicates the selector list on line 1.与源码中的消息模板一一对应。总结no-duplicate-css-selectors是 eslint-plugin-unicorn 面向 CSS 工程的重要质量规则它以上下文敏感的方式精准识别两种重复——选择器列表内的重复单项以及同一 at-rule / 嵌套 / 层叠上下文中的重复选择器列表同时刻意忽略空白与注释差异、跳过 keyframes、宽容不同上下文与不同列表顺序从而在查错与误报之间取得平衡。结合--fix的保守自动修复、eslint/css语言插件的配置范式以及关键帧场景下与css/no-duplicate-keyframe-selectors的职责分工它是一套可直接落地的 CSS 去重检测方案。【免费下载链接】eslint-plugin-unicornMore than 300 powerful ESLint rules项目地址: https://gitcode.com/GitHub_Trending/es/eslint-plugin-unicorn创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

Windows 11 语言包界面残留中文?从原理到注册表彻底解决

Windows 11 语言包界面残留中文?从原理到注册表彻底解决

说句不客气的话,“Windows 11 装了语言包之后,部分界面还是中文”这个问题,过去一年我前前后后处理了不下三十次。有从 Win10 升级上来点错语言的老用户,有买了海外版 ThinkPad 想把系统切成英文界面的开发同事,也有折…

2026/9/19 21:50:48 阅读更多 →
esp-iot-solution 的 USB Device 解决方案全景:从 UAC/UVC 到 HID、MSC 与扩展屏

esp-iot-solution 的 USB Device 解决方案全景:从 UAC/UVC 到 HID、MSC 与扩展屏

esp-iot-solution 的 USB Device 解决方案全景:从 UAC/UVC 到 HID、MSC 与扩展屏 【免费下载链接】esp-iot-solution Espressif IoT Library. IoT Device Drivers, Documentations and Solutions. 项目地址: https://gitcode.com/GitHub_Trending/es/esp-iot-solu…

2026/9/19 21:50:48 阅读更多 →
整车厂用户运营数据链路:从埋点到CDP的精细化运营实践

整车厂用户运营数据链路:从埋点到CDP的精细化运营实践

简介:《新时代整车厂竞争法则:打造精细化用户运营》是一份面向整车厂管理者、汽车行业市场及用户运营从业者的行业报告式PDF,系统剖析汽车市场增长放缓、疫情冲击、消费者偏好迁移等新时代困境,并结合蔚来、小鹏等新势力实践&…

2026/9/19 21:49:48 阅读更多 →

最新新闻

PTO TPARTMIN 指令全解析:CANN pto-isa 中基于有效区域(valid region)的逐元素最小值选择

PTO TPARTMIN 指令全解析:CANN pto-isa 中基于有效区域(valid region)的逐元素最小值选择

PTO TPARTMIN 指令全解析:CANN pto-isa 中基于有效区域(valid region)的逐元素最小值选择 【免费下载链接】pto-isa Parallel Tile Operation (PTO) is a virtual instruction set architecture designed by Ascend CANN, focusing on tile-l…

2026/9/19 22:40:13 阅读更多 →
Python爬虫入门:Requests库HTTP请求与响应处理详解

Python爬虫入门:Requests库HTTP请求与响应处理详解

简介:这份完整版Python网络爬虫系列课程的第一讲,聚焦Requests库入门,面向零基础开发者,适合系统学习数据采集与信息提取技术。课件从HTTP请求动作切入,逐一说明构造请求、获取网页、提交表单等常见操作的区别&#xf…

2026/9/19 22:40:13 阅读更多 →
QMK Clueboard 66% 66_ansi 默认键位解析:QK_GESC 特殊键与三层按键布局设计

QMK Clueboard 66% 66_ansi 默认键位解析:QK_GESC 特殊键与三层按键布局设计

QMK Clueboard 66% 66_ansi 默认键位解析:QK_GESC 特殊键与三层按键布局设计 【免费下载链接】qmk_firmware Open-source keyboard firmware for Atmel AVR and Arm USB families 项目地址: https://gitcode.com/GitHub_Trending/qm/qmk_firmware 本文围绕 Q…

2026/9/19 22:40:13 阅读更多 →
基于Spring Boot与Vue的非遗数字化传承平台设计与开发

基于Spring Boot与Vue的非遗数字化传承平台设计与开发

1. 为什么要做非遗数字化这个选题先说我自己的结论:非遗类系统是计算机毕业设计里少有的“高分潜力股”。为什么?因为它天然具备三层价值——文化层面有社会意义,技术层面能覆盖主流前后端技术栈,应用层面有真实的使用场景。很多同…

2026/9/19 22:40:13 阅读更多 →
为什么blessed渲染这么快?深度解析CSR、BCE与damage buffer的屏幕优化技巧

为什么blessed渲染这么快?深度解析CSR、BCE与damage buffer的屏幕优化技巧

为什么blessed渲染这么快?深度解析CSR、BCE与damage buffer的屏幕优化技巧 【免费下载链接】blessed A high-level terminal interface library for node.js. 项目地址: https://gitcode.com/gh_mirrors/bl/blessed blessed 是一个专为 node.js 打造的高级终…

2026/9/19 22:40:13 阅读更多 →
ESP32 USB Host 方案全解析:Camera/Audio/4G 网络/存储/Hub 五大应用实战指南

ESP32 USB Host 方案全解析:Camera/Audio/4G 网络/存储/Hub 五大应用实战指南

ESP32 USB Host 方案全解析:Camera/Audio/4G 网络/存储/Hub 五大应用实战指南 【免费下载链接】esp-iot-solution Espressif IoT Library. IoT Device Drivers, Documentations and Solutions. 项目地址: https://gitcode.com/GitHub_Trending/es/esp-iot-solutio…

2026/9/19 22:39:12 阅读更多 →

日新闻

BP神经网络时序预测:滑窗长度与多窗口平均策略

BP神经网络时序预测:滑窗长度与多窗口平均策略

简介:面向机器学习、深度学习与数据建模学习者的一份完整研究文献,聚焦BP神经网络在农业产量预测中的应用。文档以1980—2018年全国棉花产量为样本,系统讲解数据归一化处理、激活函数原理、多层神经网络结构搭建及训练流程,展示敏…

2026/9/19 0:00:30 阅读更多 →
Transformer训练实时监控实战:基于MindSpore的损失曲线可视化方案

Transformer训练实时监控实战:基于MindSpore的损失曲线可视化方案

上个月调一个Deformable DETR模型,在单卡上要跑将近两天。第二天早上我下意识打开终端翻日志,发现loss从凌晨两点就开始往上爬,一路从0.8涨到1.35,整整六个小时没人发现。那六个小时的训练不仅白跑,还霸占着卡——等于…

2026/9/19 0:00:30 阅读更多 →
OpenCloud 中的 Go 类型安全转换库 spf13/cast:从零值回退到泛型 API 的完整实战指南

OpenCloud 中的 Go 类型安全转换库 spf13/cast:从零值回退到泛型 API 的完整实战指南

OpenCloud 中的 Go 类型安全转换库 spf13/cast:从零值回退到泛型 API 的完整实战指南 【免费下载链接】opencloud 🌤️ OpenCloud is the open source platform for file management, sharing and collaboration. Simple and sovereign. 项目地址: htt…

2026/9/19 0:00:30 阅读更多 →

周新闻

AI SDK Harness 依赖更新指南:掌握 harness 包 SDK 依赖的升级、桥接同步与一致性校验

AI SDK Harness 依赖更新指南:掌握 harness 包 SDK 依赖的升级、桥接同步与一致性校验

AI SDK Harness 依赖更新指南:掌握 harness 包 SDK 依赖的升级、桥接同步与一致性校验 【免费下载链接】ai The AI Toolkit for TypeScript. From the creators of Next.js, the AI SDK is a free open-source library for building AI-powered applications and ag…

2026/9/19 3:59:36 阅读更多 →
Refine v5 Ant Design NumberField 组件实战:基于 Intl 的本地化数字格式化

Refine v5 Ant Design NumberField 组件实战:基于 Intl 的本地化数字格式化

Refine v5 Ant Design NumberField 组件实战:基于 Intl 的本地化数字格式化 【免费下载链接】refine A React Framework for building internal tools, admin panels, dashboards & B2B apps with unmatched flexibility. 项目地址: https://gitcode.com/GitH…

2026/9/19 3:53:08 阅读更多 →
Flutter应用改名全指南:从Android到iOS的配置与工具实践

Flutter应用改名全指南:从Android到iOS的配置与工具实践

刚接一个外包项目时,甲方要求把工程里临时用的应用名改成正式产品名。我本来觉得“改名”这种小事,打开配置文件改一行不就完了?结果真动手才发现,Flutter项目里“应用名称”根本不是一处配置,而是一整套散落在 Androi…

2026/9/19 4:02:43 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/16 22:31:27 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/19 17:50:38 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/16 22:32:59 阅读更多 →