小编典典

无效的CSS选择器会导致规则被放弃:基本原理是什么?

css

我正在寻找指向邮件列表讨论等的链接,而不是进行猜测。

谁能帮我找出CSS选择器3级规范中引用的错误处理规则背后的理由。

用户代理必须遵守处理解析错误的规则:

  • 包含未声明的名称空间前缀的简单选择器无效
  • 包含无效简单选择器,无效组合器或无效令牌的选择器无效。
  • 包含无效选择器的一组选择器无效。

重用规范的选择器必须定义如何处理解析错误。(对于CSS,将删除使用选择器的整个规则。)

我有以下规则:

#menu li.last, #menu li:last-child {
  ...
}

为了弥补IE8缺乏对后代的支持,我使用了一个类和一个JavaScript填充程序。但是,这没有用,因为IE8符合CSS在错误处理方面的规范,并且由于无法识别一个选择器而放弃了整个规则。可以通过将两个选择器分成单独的规则来解决此问题。

为什么这是可取的? 规范为何不建议仅丢弃无法识别的选择器,而保留其余规则?

我想知道其基本原理,因为目前这些规则似乎违反直觉。


阅读 654

收藏
2020-05-16

共1个答案

小编典典

为什么这是可取的? 规范为何不建议仅丢弃无法识别的选择器,而保留其余规则?

简短的答案是,对于实现而言,要弄清楚究竟是什么构成“规则的其余部分”(或“选择器列表的其余部分”),而又不会弄错它,又会不经意地弄乱布局,将是非常困难的,以及在错误处理方面的一致性以及与未来规范的向前兼容性。


关于处理无效选择器的。关于该答案的评论直接指向CSS2.1规范的第4.1.7节中的 “处理规则集中选择器中的错误”,其中以选择器中的逗号为例。我认为它很好地总结了一下:

CSS 2.1为选择器中的逗号(,)赋予了特殊含义。但是,由于不知道逗号是否会在将来的CSS更新中获取其他含义,因此即使选择器的其余部分在CSS
2.1中看起来很合理,如果选择器中的任何地方出现错误,也应忽略整个语句。

虽然逗号本身仍然意味着就选择器而言将两个或多个选择器进行分组,但事实证明选择器4引入了新的功能性伪类,这些伪类接受选择器组(或选择器列表)作为参数,例如:matches()(甚至会更改:not(),接受列表,使其类似于:matches(),而在级别3中,它仅接受一个简单的选择器)。

这意味着不仅可以找到与规则关联的选择器的逗号分隔组,而且还可以在功能性伪类中找到它们(请注意,这仅在样式表中;在CSS之外,选择器可以出现在样式表中)。选择器库和本机SelectorsAPI所使用的JavaScript代码。

尽管到目前为止,这并不是唯一的原因,但仅此一个因素就足以使解析器的错误处理规则变得过于复杂,并具有破坏选择器,规则集甚至布局的巨大风险。如果出现逗号解析错误,解析器将无法确定此选择器组是对应于整个规则集还是其他选择器组的一部分,以及如何处理其余选择器及其相关规则集。最安全的选择不是放弃猜测,冒着错误猜测并以某种方式违反规则的风险(例如,通过匹配和设置所有错误元素的样式),而是放弃规则并继续前进。

例如,考虑以下规则,该规则的选择器在第4级有效,但在第3级无效,该规则取自我的这个问题:

#sectors > div:not(.alpha, .beta, .gamma) {
    color: #808080;
    background-color: #e9e9e9;
    opacity: 0.5;
}

不了解选择器4的幼稚解析器可能会尝试将其拆分为三个共享相同声明块的不同选择器,而不是仅使用逗号将单个选择器与具有接受列表的伪类的选择器分开:

#sectors > div:not(.alpha
.beta
.gamma)

如果仅丢弃显然无效的第一个选择器和最后一个选择器,而保留第二个选择器有效,那么它是否应尝试将规则应用于具有class的任何元素beta?显然,这不是作者打算做的,因此,如果浏览器这样做,它将对这种布局产生意想不到的事情。通过使用无效的选择器丢弃规则,布局看起来会更聪明一些,但这是一个过于简化的示例;如果使用不当,具有更改布局样式的规则可能会导致更大的问题。

当然,选择器解析中也可能出现其他歧义,这可能导致以下情况:

  • 不知道复杂选择器在哪里结束
  • 不知道选择器列表在哪里结束
  • 不知道声明块从哪里开始
  • 结合以上

同样,通过丢弃规则集而不是玩猜测游戏,最容易解决所有这些问题。

对于似乎无法识别的:last-child格式正确的选择器(例如您的示例中的伪类),规范不会在无法识别的选择器和纯格式错误的选择器之间进行区分。两者都导致解析错误。在您链接到的同一部分中:

无效是由解析错误引起的,例如无法识别的令牌或当前解析点不允许的令牌。

通过做出这样的陈述,:last-child我假设浏览器首先能够解析单个冒号,后跟任意标识作为伪类;在现实中你不能假设的实现会知道解析:last-child为一个伪类正确,或类似的东西:lang():not()与功能性的符号,因为功能的伪类没有出现,直到CSS2。

选择器定义了一组特定的已知伪类和伪元素,其名称很可能在每个实现中都经过硬编码。解析器最天真有 整个
每个伪类和伪元素,包括单/双冒号(S),硬编码的符号(如果主流浏览器实际上做到这一点,我不会感到惊讶:before:after:first-letter:first-line作为特殊情况)。因此,对于一个实现来说,看起来像是伪类的东西很可能对另一个实现来说是个傻瓜。

由于实现失败的方法有很多,因此规范没有区别,使错误处理更加可预测。如果无法识别选择器,则无论是由于不支持选择器还是畸形选择器,都将丢弃该规则。简单,直截了当,而且很容易引起您的注意。


综上所述,在www风格的公共邮件列表中至少有一项讨论建议更改规范,因为毕竟通过拆分选择器来实现错误处理可能并不那么困难。

我还应该提到一些布局引擎的行为有所不同,例如WebKit忽略规则中非WebKit前缀的选择器,使用其自己的前缀,而其他浏览器则完全忽略该规则(您可以找到更多示例;这里略不同的。可以说,尽管有那些带前缀的选择器,但WebKit确实试图巧妙地解析逗号分隔的选择器组,因此可以说它正在绕过规则。

我认为工作组还没有令人信服的理由来改变这种行为。实际上,如果有的话,他们有充分的理由 不对其进行更改
,这是因为网站多年来一直依赖这种行为。过去,我们有选择器技巧来过滤IE的较早版本。今天,我们为筛选器添加了前缀选择器。这些黑客都依赖于某些浏览器的相同行为,即丢弃他们无法识别的规则,而其他浏览器在认为正确的情况下会应用它们,例如,通过识别前缀(或像WebKit一样仅丢弃无法识别的前缀)。如果要更改此规则,则网站可能会破坏这些浏览器的较新版本,这绝对不可能在像我们这样的多元化(分散的)Web中发生。

截至[2013年4月],由于我在上面假设的原因,在电信设备中决定此行为保持不变:

   -解决:请勿对选择器采用MQ样式的无效化
               由于Web兼容问题。

媒体查询样式无效是指用逗号分隔的列表中的无效媒体查询 没有 破坏整个@media规则。

2020-05-16