`)都有下边框,但想排除那些是标题(`
` 并且是其父元素的第一个孩子。
2. 类型选择器 (`p`): 结合了标签名。
3. 类选择器 (`.container`): 结合了类名。
4. 伪类 (`:firstchild`): 这是一个状态选择器,其判断依赖于元素在其父元素内的位置和同胞元素的类型。
让 `:not()` 能够正确地处理这种层层嵌套、条件关联的复杂选择,对浏览器解析器来说,意味着它需要能够“负向”理解所有这些规则的逻辑。换句话说,浏览器不仅要知道“是什么”,还要知道“不是什么”,而且这个“不是什么”可能本身就包含了一系列的“是”的条件。
从浏览器的渲染引擎的角度来看,性能是至关重要的。浏览器在解析CSS时,需要将选择器转化为能够高效查找DOM元素的数据结构。当选择器变得非常复杂,特别是包含否定性的复杂组合时,这种转换和查找的成本会急剧上升。
查找效率: 如果 `:not()` 内部是一个非常复杂的组合,浏览器可能无法像处理简单选择器那样,直接从DOM树的特定层级开始高效查找。它可能需要先遍历一大批潜在的元素,然后逐一检查它们是否符合 `:not()` 内部的否定条件。如果 `:not()` 内部的条件本身就很耗费计算资源(例如,复杂的链式伪类),那么在否定它的过程中,计算量更是成倍增加。
可预测性: 浏览器引擎的设计,倾向于将复杂性“压平”或“优化”到可以理解和预测的模式。允许 `:not()` 接受任意复杂的选择器,会极大地增加解析和执行的不确定性,使得优化变得异常困难。
另一方面,CSS语言本身也在不断发展。对于 `:not()` 的限制,也存在一些历史原因和设计哲学。早期的CSS标准在设计时,更侧重于清晰、可预测的声明式样式。过于激进的复杂性,可能会让CSS变得难以学习和维护,也容易引入意想不到的渲染结果。
CSS Working Group 在不断权衡新特性的能力边界和对现有生态的影响。允许 `:not()` 支持任意复杂选择,可能会导致:
浏览器兼容性问题: 不同的浏览器引擎在解析和实现复杂否定选择器上的差异会非常大,导致跨浏览器兼容性成为噩梦。
性能瓶颈: 如前所述,对性能的影响难以估量。
可读性与维护性: 开发者在阅读和调试一个包含深层嵌套 `:not()` 的样式表时,可能会感到非常吃力。
因此,CSS规范(如CSS Selectors Level 4)对 `:not()` 的参数做出了限制,通常只允许它接受一个“简单选择器”。简单选择器是指不包含伪元素(如 `::before`)或组合符(如 `>`、`+`、`~`)的单一选择器,如标签名 (`p`)、类名 (`.myclass`)、ID (`myid`)、属性选择器 (`[type="text"]`),以及某些基本的伪类(如 `:firstchild`, `:nthchild()`),但即便这些基本的伪类,也不能随意嵌套在 `:not()` 内部,其接受的伪类也有一定范围。
尽管如此,CSS Working Group 也在不断审视和改进标准。一些更新的标准(如 Selectors Level 4)允许 `:not()` 接受更广泛的简单选择器,比如属性选择器和某些伪类,但这仍然不是任意的“复杂选择”。
简而言之,`:not()` 不支持复杂选择,不是因为不能,而是基于对浏览器性能、解析效率、语言设计哲学以及未来兼容性发展的综合考量。它被设计成一个相对聚焦的工具,用于简单的排除场景,而不是一个可以无限嵌套、组合的万能选择器构建器。如果需要更复杂的排除逻辑,开发者通常会选择通过JavaScript来辅助实现,或者调整HTML结构和CSS类名来规避这种复杂性。
实际上,最近的selector 4的草案是支持的。不仅是你给的例子(compound selector)支持,实际支持selector list(即所有选择器)。
【以下是我的主观看法,不保证准确,谨供参考。如需验证,请自行查阅w3c mailing list记录,或写邮件咨询spec的编辑,比如
fantasai和
Tab Atkins Jr.。】
过去(selector 3规范)确实仅支持单个simple selector。
我们需要理解,技术上可以做到不代表就应该直接上。
首先我们应该考虑需求,即实际的use cases。单个simple selector其实已经满足了大量需求了。对于简单的compound selector的需求,比如`a:not(.b.c)`,可以写作`a:not(.b):not(.c), a.b:not(.c), a.c:not(.b)`。题主写的`img:not(.abc[alt][href])`(这里href估计是题主的笔误,因为img上只有src属性)也可以转写。当然,这比较麻烦,且如果多的话,很容易出现组合爆炸。不过当初连简单的:not都没有,人民群众并不习惯逆向思维,更复杂的需求还没有被发掘,也就是并没有很多use cases。
其次,我们是希望新特性出来非常慢但是一步到位,还是先出一部分特性用起来呢?总的来说,后者更好。因为更快出可用的新特性,大家可以更快试验,也就可以更快的给出反馈,厂商可以更快的发现和修复bug,标准工作组可以更快地确认真实的use cases,确认spec的设计是可行和合理的。此外,小步走可以在工程上控制复杂度,避免出现步子迈得太大扯到蛋。(比如CSS2就是一个反例。当初标准过于复杂,就不可能有足够完善和完全的实现,各浏览器实现存在各种bug不说,更有许多是spec本身存在bug、未定义或含糊不清的地方。)当然,“小步走”的前提是你本身是有设计有规划的。现在一些公司所谓的“小步走”实际是“快糙猛”,请大家注意甄别,千万别混为一谈。【PS. “小步走”也绝不等于“摸着石头过河”——所谓“摸石头过河”是一种非常恶心的做法,因为其实质是忽悠大家连救生圈都不带就下河,你若渡河成功算领导高瞻远瞩指挥有方,你若不幸淹死就成了领导嘴里不可避免要付出的代价然后被遗弃。】
具体到`:not`,仅支持单个simple selector意味着可将:not简单视为一种新的simple selector,从工程师的角度看,可以完全不改动selector引擎的原有设计和实现,实现起来很容易。而支持复杂的:not或者:matches则意味着必须支持一种以前从未有过的嵌套结构,虽然看起来也不是很难,但数据结构、匹配流程、优化算法很可能全都要改,实际工作量大许多。
此外,selector是有性能要求的。这是为什么在css3 selector之前没有任何需要回溯计算的选择器。:not也存在性能上的问题。不难看出,其内部如果是compound selectors,性能和不带:not的相同compound selectors并不会有什么差别。但是如果里面有combinator,这个复杂度就不好判断了。所以之前草案一直规定css匹配时,:not、:matches等只能包含compound selectors,只有调用js的selectors api时才支持完整selectors。不过最近的草案去除了大部分限制,只保留了对:has的限制。这应该是浏览器厂商的工程师已经完成了对性能影响的评估——这个事情不是光靠嘴巴说说的,一定是需要真的实现出来然后测试验证的。这也是为什么这些新的特性不是一蹴而就的。
以上。
本站所有内容均为互联网搜索引擎提供的公开搜索信息,本站不存储任何数据与内容,任何内容与数据均与本站无关,如有需要请联系相关搜索引擎包括但不限于百度,google,bing,sogou 等
© 2025 tinynews.org All Rights Reserved. 百科问答小站 版权所有