属性选择器匹配发生在样式计算阶段,浏览器在构建dom节点时即流式执行cssmatcher.match(node),而非等待页面加载完成;[type="submit"]等选择器在input节点创建后立即参与匹配,动态添加属性不会触发重匹配。

属性选择器匹配发生在样式计算阶段,不是渲染时才执行
浏览器在构建 DOM 节点的同时,就对每个节点执行 CSS 选择器匹配——cssMatcher.match(node) 是流式调用的,不是等整个页面加载完再批量扫。这意味着 [type="submit"] 这类选择器,会在 <input> 节点创建后立刻参与匹配,而非等到 document.styleSheets 解析完成。
常见错误是以为“写个 [data-id] 就能懒加载样式”,其实它早已被纳入匹配流水线;若该属性后期 JS 动态添加,不会触发重匹配——CSS 不监听 DOM 属性变更。
- 匹配只基于当前节点及其祖先链,不查兄弟或后代(后代选择器如
form [type="text"]是另一层逻辑) - 属性名区分大小写,
[Type="text"]在 HTML 文档中永远不匹配type="text" - HTML 中布尔属性如
disabled写成<button disabled></button>时,[disabled]能匹配;但写成<button disabled></button>也一样生效
[attr] 和 [attr="val"] 的底层开销差异很小,但语义完全不同
[attr] 只检查属性是否存在,引擎直接查 DOM 节点的 attributes Map,接近 O(1);[attr="val"] 需取值后做字符串全等比较,多一次内存读取和比对。但两者在现代浏览器中性能差距微乎其微,真正影响性能的是选择器复杂度本身——比如 div#main section[data-type="card"] > .item:hover 这种复合选择器,匹配成本远高于单个属性选择器。
容易踩的坑是误以为 [class] 可以替代 .my-class:它会选中所有带 class 属性的元素,包括 class="" 或 class=" ",而类选择器天然跳过空值。
-
[lang="en"]不匹配lang="EN",即使 HTML 规范说 lang 值不区分大小写——CSS 匹配纯按字面 -
[data-id="123 abc"]必须加引号,否则解析器截断为data-id="123",空格后内容被丢弃 - 避免在高频更新区域(如动画帧内操作的列表)大量使用
[data-*="xxx"],不是因为慢,而是它无法被 CSS 引擎缓存优化(不像 ID 或 class 有哈希索引)
~=、^=、$=、*= 这些“伪正则”不支持转义和通配符,只是朴素字符串操作
它们不是正则表达式,[href*="http://"] 不能写成 [href*="http:\/\/"],反斜杠会被当作普通字符处理;[class^="btn-"] 匹配 class="btn-primary",但不匹配 class="primary btn"——它只看属性值开头,不管单词位置。
最常误用的是 [data-tags~="react"]:它要求 data-tags 值必须是空格分隔的单词列表(如 data-tags="react vue next"),而不是 JSON 或逗号分隔。一旦写成 data-tags="react,vue",~="react" 就完全失效。
-
[attr|="en"]用于语言子标签匹配,lang="en-US"可被[lang|="en"]匹配,但[lang^="en"]也能达到同样效果,且更直观 -
[href$=".pdf"]对大小写敏感,doc.PDF不会匹配,需写成[href$=".pdf"], [href$=".PDF"]或改用 JS 动态加 class - 所有这些选择器都**不支持 Unicode 正则标志**,
i标志仅在部分浏览器中对属性值匹配有效(如[type="SUBMIT" i]),但非标准,不要依赖
data-* 属性是唯一可安全用于 JS/CSS 协同的桥梁,但匹配不能代替状态管理
CSS 属性选择器可以选中 [data-status="done"],但它只反映快照,不感知状态变更。真正控制交互逻辑的必须是 JS:监听数据变化 → 计算依赖 → 显式设置 disabled、aria-disabled 或切换 class。靠 button[data-prereq~="task-1"]:disabled 写死样式,等于把业务逻辑锁死在 CSS 里,后续任何动态解锁都会失效。
自定义元素中更需注意:attributeChangedCallback 必须显式监听 data-prereq,且每次变更都要重新校验依赖项是否满足——DOM 属性变了,CSS 不会自动重跑匹配,JS 也不会自动重算。
- HTML 属性只声明“意图”,JS 才负责“履约”;把状态判断塞进 CSS 选择器,等于放弃可控性
- 多个依赖项用逗号分隔(
data-prereq="a,b,c"),别用空格——易与 class 混淆,split(' ')对多余空格极脆弱 - 服务端渲染时,若依赖状态未就绪,宁可不写
data-status属性,也不要写data-status="pending"后让 CSS 错误匹配
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











