ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

vscode-gitlens 现代 CSS 选择器与状态化样式指南::has()、:focus-visible 与 Shadow DOM 样式 API 的工程化实践

vscode-gitlens 现代 CSS 选择器与状态化样式指南::has()、:focus-visible 与 Shadow DOM 样式 API 的工程化实践 开发工具版本控制【免费下载链接】vscode-gitlensSupercharge Git inside VS Code and unlock untapped knowledge within each repository — Visualize code authorship at a glance via Git blame annotations and CodeLens, seamlessly navigate and explore Git repositories, gain valuable insights via rich visualizations and powerful comparison commands, and so much more项目地址https://gitcode.com/gh_mirrors/vs/vscode-gitlens点击查看免费下载本篇指南以 vscode-gitlens 仓库内置的modern-css技能文档.claude/skills/modern-css/references/selectors.md为主体系统讲解现代 CSS 选择器、状态化样式、伪类以及 Shadow DOM 样式 API 的选用纪律与实战用法。你将掌握:has()取代 JS 父级感知、:focus-visible替代:focus的迁移策略、:host/::part/::slotted()/自定义属性四件套的组件样式边界划分以及如何在 Lit 组件代码库中落地这些规则——并对照 vscode-gitlens 的 webview 源码src/webviews/apps/找到每一类选择器的真实应用实例。定位这份文档在仓库中的角色.claude/skills/modern-css/是 vscode-gitlens 为 AI 协作与开发纪律维护的一组 CSS 技能参考共七个 leaf 文件selectors.md、cascade.md、layout.md、responsive.md、performance.md、theming.md、animation.md。其入口 SKILL.md 规定任何涉及 CSS 的新增、编辑、审计、重构或评审都必须先运行检测脊柱浏览器目标 → token 体系 → 样式边界再按路由表加载对应参考文件其中编写选择器、状态化样式、伪类或编写/消费 Web 组件样式时必须读取的就是本文selectors.md。这与仓库的实际情况高度相关vscode-gitlens 的 webview 界面提交图、提交详情、设置面板、时间线等位于src/webviews/apps/由大量 Lit Web Components 构成样式以.css.ts中的 Litcss模板字符串和.scss两种形态存在同时深度依赖 VS Code 主题 token--vscode-*。因此选择器知识不只是好看的语法而是决定组件样式封装、主题响应、键盘可达性的工程约束。纪律规则Discipline rules原文以三条硬性纪律开篇它们是后续所有特性的决策依据:has()优先于 JS 父级感知。需要基于子元素或后继元素的状态来影响父元素时先考虑:has()而不是在 JS 里手动切换父级 class。绝不从外部用后代选择器穿透 Shadow DOM。组件样式封装是特性而非障碍外部只能通过组件作者暴露的::part、::slotted或自定义属性 API 来定制。焦点环几乎总是用:focus-visible而不是:focus。鼠标点击时不应该出现焦点环只有键盘导航等用户确实需要的场景才应显示。这三条在仓库的可访问性规范中得到呼应docs/accessibility.md 明确要求焦点轮廓必须可见禁止在没有替代可见指示器的情况下使用outline: none避免:focus与:focus-visible同时导致的双重轮廓。特性详解从父级感知到组件边界:has() —— 基于内容的父级/关系选择Baseline新近可用预计 2026 年中广泛可用。在 vscode-gitlens 的语境下SKILL.md 的检测脊柱规定package.json存在engines.vscode且带有browser入口时目标为Baseline widely available——因此在未确认目标支持前需谨慎使用。用途父级/关系选择。依据元素包含什么或其后跟随什么来选择元素本身取代大量父级感知的 JS 模式例如根据子组件状态切换父级 class 的脚本、兄弟状态库。优先于基于子状态的 JS 父级 class 切换、兄弟状态库。/* 包含图片的卡片图片出现时切换网格行布局 */ .card:has(img) { grid-template-rows: auto 1fr; } /* 含无效输入的表单整表单标红 */ form:has(input:invalid) { border-color: var(--color-error); } /* 后面还跟着另一个列表项的项加分隔线 */ li:has( li) { border-block-end: 1px solid var(--border); }第三个例子体现了:has()的关系选择能力:has( li)表示该元素的后继兄弟是 li等价于除最后一项外都加底边框——一个过去必须靠li li { border-top }或 JS 才能完成的经典列表分隔线需求。仓库实例GitLens 提交图组件 gl-commit-box.css.ts 用:has()感知文本输入状态.message:has(.textarea:not(:placeholder-shown)) .controls { … }即当消息文本框中输入了内容:not(:placeholder-shown)时调整 controls 区样式——纯 CSS 完成了过去需要监听input事件、切换 class 的 JS 逻辑。同类用法还出现在 gl-details-wip-header.css.ts:has( .graph-details-header__issues)兄弟感知、gl-graph-scope-popover.css.ts:has(gl-checkbox[disabled])子元素状态感知以及 graph.scss 中:root:has(前缀的暗色主题混入。:is() / :where() / :not() —— 分组与特异性控制这三个选择器在cascade.md中完整展开见 cascade.md核心结论如下:is()消除选择器重复但取参数列表中最高特异性——:is(#id, p)拥有 ID 级特异性。:where()与:is()完全相反的兄弟——零特异性适合写容易被覆盖的基础/重置样式。:not()否定选择支持逗号分隔的多参数特异性规则与:is()相同取参数列表最高者。/* :is() —— 分组但不降特异性 */ :is(header, main, footer) h2 { margin-block: 1rem; } /* :where() —— 零特异性基础样式随时可被覆盖 */ :where(h1, h2, h3) { margin: 0; } /* :not() —— 多参数否定 */ button:not([disabled], .secondary) { background: var(--accent); }仓库实例action-item.tsGitLens 共享的操作按钮组件中可见:is()的分组用法a:is(:hover, :focus, :active) { text-decoration: none; }:focus-visible —— 只在真正需要时显示焦点环Baseline广泛可用。用途仅在用户确实需要焦点可见时键盘导航显示焦点环鼠标点击不触发。优先于:focus。:focus在键盘和鼠标下都会触发:focus-visible只在 UA 判定焦点应当可见时触发。迁移策略重点禁止盲目全局替换(a) 作用在input、textarea、select上的:focus是正确的保留——这些控件始终需要显示焦点(b) 作用在按钮、链接、自定义交互元素上的:focus迁移到:focus-visible(c) 超出焦点环本身、用作状态指示如点击后的背景/边框变化的:focus需要先做设计评审再决定每次迁移后都要用键盘逐项测试导航。button:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }仓库实例GitLens 的共享无障碍样式片段 a11y.css.ts在 action-item.ts 中通过focusOutline引用正是焦点环的落地实现docs/webview-accessibility-patterns.md 还展示了将:has()与:focus-visible组合的进阶模式.gl-graph__ref-pill:has(chip:focus-visible) …用:has()在键盘聚焦到内部 chip 时同步高亮整个胶囊。:focus-within —— 后代获得焦点时高亮祖先Baseline广泛可用。用途任一后代获得焦点时样式化父元素适合表单组、下拉容器、输入框包装器。优先于用 JS 焦点冒泡事件处理器切换父级 class。.search-bar:focus-within { box-shadow: 0 0 0 2px var(--accent); }仓库实例action-item.ts 在:host上使用:host(:focus-within)注入focusOutline并让:host(:hover)与:host(:focus-within)共享悬停背景——当组件内部链接获得焦点时整个按钮呈现聚焦态。:host 与 :host() —— Shadow DOM 内部的宿主样式Baseline广泛可用。:host从 Shadow DOM 内部样式化 shadow root 的宿主元素定义组件自身的默认样式:host { display: block; contain: content; }:host()宿主匹配指定选择器时应用样式实现基于宿主属性或 class 的条件化组件样式:host(.compact) { padding: 0.25rem; } :host([disabled]) { opacity: 0.5; pointer-events: none; }仓库实例:host在 GitLens 每个 Lit 组件中几乎都是标配。docs/webview-styling.md的架构检查清单对应下文架构检查一节特别要求所有组件都应设置:host { display: … }。真实案例action-item.ts 的:host声明了display: inline-flex、尺寸与border-radius: var(--gl-radius-sm)并同样使用:host([disabled])处理禁用态pointer-events: none; opacity: 0.5与原文示例逐行对应。:host-context() —— 已废弃的祖先感知Baseline受限——仅 Chromium 支持Firefox 从未实现Safari 部分支持。已废弃——CSS WG 已决议将其移出规范。用途当祖先匹配某选择器时样式化宿主。警告不要在跨浏览器代码中使用。Firefox 不支持且未来也不会支持。改用自定义属性或显式宿主属性。/* 已废弃 —— 跨浏览器代码中避免使用 */ :host-context([data-themedark]) { --component-bg: #1a1a1a; } /* 推荐替代自定义属性穿透 shadow DOM */ :host { background: var(--component-bg, #fff); }仓库实例现实权衡尽管文档明令避免从源码看 GitLens 在 VS Code 集成场景中仍保留了一处:host-context使用——如 account-chip.ts 与 access-account.ts 中用:host-context(.vscode-dark)/:host-context(.vscode-light)检测 VS Code 的宿主主题类。这解释了docs/webview-styling.md中为什么强调自定义属性穿越 shadow boundary 才是可靠信号media (forced-colors)只反映操作系统级强制色彩而.vscode-high-contrast祖先类位于 shadow boundary 之外——继承的自定义属性是唯一同时覆盖两条路径的机制。可以推断这些:host-context残留是历史实现新代码应遵循本文档规则。::part() —— 面向消费者的组件样式 APIBaseline广泛可用。用途Web 组件的消费侧样式 API。组件作者显式暴露命名 part消费者在外部样式化它们。优先于用后代选择器穿透 shadow DOM这根本不生效。Gotchapart 必须由组件作者通过part属性显式暴露。只有暴露的表面可被样式化——这是特性而非限制公共 API 面需要刻意设计。/* 组件 shadow DOM 模板内 */ /* button partcontrolClick me/button */ /* 组件外部 */ my-component::part(control) { background: var(--accent); border-radius: 0.25rem; }::slotted() —— 样式化插槽内容Baseline广泛可用。用途从 light DOM 插入 shadow DOM 的元素slot 内容的样式。只匹配顶层的被插槽子元素不匹配其后代。Gotcha::slotted()只接受复合选择器compound selector——不允许组合器。::slotted(h2 span)与::slotted(h2 span)都非法只有::slotted(h2)或::slotted(.class)合法。::slotted(h2) { margin: 0; color: var(--heading-color); } ::slotted(*) { font-family: inherit; }仓库实例ai-input.ts 用::slotted(*)统一 footer 插槽内容的样式基线chart.ts 用::slotted([slotempty])样式化空状态占位graph.scss 中还有::slotted(*) { min-height: 0 }修复分栏面板最小高度的注释案例。自定义属性 —— Shadow DOM 主题化的主 APIBaseline广泛可用。用途CSS 自定义属性会穿过 shadow DOM 边界继承。这是不破坏封装的前提下从外部主题化 Web 组件的首要 API。优先于:host-context()已废弃、穿透 shadow DOM、JS 主题注入。/* 消费者组件外部 */ my-component { --accent: hotpink; } /* 组件shadow DOM 内部 */ :host { color: var(--accent, dodgerblue); } button { background: var(--accent, royalblue); }这正是 vscode-gitlens webview 的根基docs/webview-styling.md说明共享 token 定义在:roottokens.scss上通过自定义属性继承穿透 shadow DOM 进入每个 Lit 组件。Token 体系按前缀划分--gl-*为 GitLens 自有语义 token、--vscode-*为 VS Code 主题变量直接使用、禁止包装、--wa-*仅限 WebAwesome 组件、--gk-*已废弃。需要 VS Code 未提供的 token 时用color-mix()或相对颜色语法从--vscode-*派生禁止硬编码 hex。scope —— 无 Shadow DOM 的作用域cascade.md完整覆盖见 cascade.md作用域语法、近因特异性与陷阱。Baseline新近可用。用途不借助 shadow DOM 实现选择器作用域可用to (…)定义下界终止后代匹配。Gotchascope内部近因优先于特异性——更近的作用域根胜过更远作用域中特异性更高的选择器。同样属新近特性需确认浏览器目标支持。scope (.card) to (.card-footer) { img { border-radius: 0.5rem; } }架构检查Web 组件代码库审计清单在组件数量众多的代码库如 vscode-gitlens 的 webviews中审计或构建时原文给出五项检查::part()暴露审计组件是否暴露了 partpart 太多会形成难以维护的公共 API 面太少会迫使消费者退而使用自定义属性变通。需要审计平衡点。:host一致性所有组件是否都设置了:host { display: block; }或 inline-block、flex 等:hostdisplay 不一致是 Lit 代码库中布局 bug 的常见来源。应检查 display、contain、overflow、position 等属性的模式一致性。样式重复公共模式可滚动容器、卡片布局、列表项、空状态是否抽取为共享样式/mixin还是每个组件各自重写在 Lit 代码库中经adoptedStyleSheets即 Lit 的static styles数组共享样式是性能最优路径——样式只解析一次、跨实例共享。死 CSS在 30 个样式文件的代码库中孤立规则会不断累积。检查是否有指向已不存在元素/类的选择器。Lit 特有静态样式 vs 动态CSS 应尽可能放在static stylescss标记模板中——解析一次、全局共享。动态样式styleMap()/classMap()只应留给运行时真正变化的取值。审计应检查属于静态样式的 CSS 是否泄漏进了渲染期逻辑。反模式清单本类别用.my-component .internal-element穿透 shadow root——不生效。改用::part、::slotted或自定义属性。用:focus做键盘可见的焦点环——改用:focus-visible迁移策略见上文。在 JS 里重造父级感知——:has()原生就能做。在跨浏览器代码中使用:host-context()——已废弃且 Firefox 不支持。改用穿过 shadow boundary 继承的自定义属性或宿主的显式属性。::slotted(div span)——匹配不到。::slotted()只接受复合选择器不含组合器。暴露过多::part名称——形成难以维护的大型公共 API 面。暴露要克制。实战建议在 vscode-gitlens 中应用这套规则结合 SKILL.md 的检测脊柱与本文档的纪律落地路径如下先定边界新组件属shadow root 内部用:host样式自动隔离谨慎暴露::part、Web 组件消费者只用自定义属性 ::part::slotted绝不伸手进内部还是light DOM标准级联——三种边界的选择器武器完全不同。匹配 token 体系GitLens webview 中优先使用--gl-*与--vscode-*语义 tokentokens.scss颜色一律从--vscode-*派生不硬编码。按本文档逐条对照状态化样式先问:has()是否够用焦点环统一:focus-visible输入类控件保留:focus跨边界定制走::part/::slotted/ 自定义属性三件套审计时按上文五项架构检查执行并按真实条件下是否出错 → 复合型架构债 → 有可量化收益的现代化 → 纯代码质量现代化四级划分优先级。这套规则的价值在于把写 CSS从碰运气调样式变成可审计的工程决策每个选择器选型背后都有明确的边界依据、兼容性依据Baseline 状态与仓库内可对照的真实实现读者可以在src/webviews/apps/中逐一验证。赞分享开发工具版本控制【免费下载链接】vscode-gitlensSupercharge Git inside VS Code and unlock untapped knowledge within each repository — Visualize code authorship at a glance via Git blame annotations and CodeLens, seamlessly navigate and explore Git repositories, gain valuable insights via rich visualizations and powerful comparison commands, and so much more项目地址https://gitcode.com/gh_mirrors/vs/vscode-gitlens点击查看免费下载创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表