场景
当鼠标悬停在具有 .dropdown 类的元素上时,相邻的上一个元素 .menuItem 会被选中。
<div class="menuItem" />
<div class="dropdown" />
错误示范
.dropdown {
&:hover {
~ .menuItem {
// css
}
}
}
错误原因
MDN中对于这么说兄弟元素选择器有这么一段话,强调了after,CSS中有~来选中所有后续兄弟元素,+来选中紧邻的后续兄弟元素,但CSS中其实是没有方法可以选中该元素之前的元素的。
为什么没有前一个兄弟元素的选择器
以下几段文字来源于 wonderlust91.github.io/
查阅资料后发现,诸如 查找子元素的直接父元素、查找子元素的祖先元素、查找某元素的前一个紧邻兄弟元素 这样的选择器,CSS 中都未实现。因为这样的选择器会导致回溯。
浏览器设计之初就考虑了渐进显示,文档加载了多少就显示多少内容,而不用等整个文档下载完成。
渐进显示在 CSS 上的原理就是一个节点所适用的样式只取决于它和它之前的节点(父节点或它之前的兄弟节点)。而上面举例的选择器都恰好相反,即当浏览器解析到一个新节点时,可能改变之前节点所适用的样式,这违背了前面的原理,一个节点的样式被他之后的节点改变了。这就要求在解析一个新节点后,得回头重新计算之前节点所匹配的样式,这就是所谓的“回溯”。最坏的情况就是导致大量的重新计算,相当于重新渲染整个网页。
因此 CSS 直到 2.1 都没有引入任何可能引起回溯的选择器,但从 CSS3 开始,如 :last-child 等类似选择器,会造成回溯。
CSS2 中所有选择器在读入一个起始标签(start tag)后,就确定了是否匹配。但对于 CSS3 中的 :last-child 伪类要判断这条规则是否适用,至少要在结束标签(end tag)后再读入一个标签才能确定,如果是父元素的结束标签,则匹配成功,否则匹配失败。假设浏览器渐进显示了部分内容,我们对某个元素应用了 :last-child 伪类样式,这可能出现加载过程中元素并未应用到伪类提供的样式,直到加载完成后才应用成功。
正确做法
.menuItem:has(~ .dropdown:hover) {
// css
}