【问题标题】:How to have an arbitrary selector in CSS?如何在 CSS 中使用任意选择器?
【发布时间】:2017-02-22 19:10:02
【问题描述】:

如何在 CSS 规则中添加任意选择器?

例如,假设我想让.effect 类的每个项目在用户悬停在#target 上时变为红色。我将如何实现这一点?有没有一种强大的方法来解决这个问题?我知道诸如在#target 中嵌套.effect 或使用兄弟选择器~+ 之类的事情,但所有这些都依赖于某种构造HTML 的方式。

这可能吗?这似乎是一件相对简单的事情。如果不可能,有什么理由不可以吗?

我不想使用 Javascript。

【问题讨论】:

  • 你的 HTML 的结构是什么?
  • @Vucko 不,这不会影响.effect 元素外部 #target
  • @Daniel_ZA:我正在寻找与布局无关的解决方案。我已经知道当它们嵌套或兄弟时该怎么做。
  • @Vucko OP 明确写道,他知道如何在 .effect 嵌套或同级的情况下做到这一点。所以问题显然是关于元素的问题 outside #target.
  • 我想说您需要通过客户端逻辑(javascript)设置一些全局状态,因为 css 由于其“级联”性质而不会提供向上迭代。对于不存在的内容,您需要类似 having() 的选择器。

标签: css


【解决方案1】:

不,你不能。

在可预见的未来也不要指望它。让我们来看看为什么!

从从事 CSS 引擎工作的人的角度来看,选择器实际上是向后评估。这当然是 CSS 的一个相当有趣且鲜为人知的方面。虽然 CSS 选择器规范没有直接定义实现行为,但所有选择器的定义都考虑到了这一点。没有创建可以在 DOM 中任意跳转的分层/“结构”选择器,因为与我们今天的相比,这会导致严重的性能问题。

因此,例如,让我们采用以下选择器:

#target:hover .effect

这要求类为 effect 的元素是 ID 为 target 的元素的子元素(在任何深度),因为选择器引擎以 匹配开始首先是 effect 类的元素,然后继续向后工作,在 DOM 中逐步查找 ID 为 target 的父元素。

跳转到父节点非常快。向前评估这一点将涉及测试 ID 为 target 的任何元素的所有子元素,这会大大提高性能。

CSS 评估的这一特性自然对性能很重要;在最坏的情况下,上面的选择器只会冒泡到 DOM 的根,一路上只测试少数元素。例如,直接子选择器a > b 仅测试直接父然后停止。

“烘焙”选择器的结构

为了进一步提高性能,选择器的 结构 被“烘焙”到 DOM 中。 There certainly isn't consensus on this, i.e. every CSS engine does it differently, but roughly when the DOM structure of a selector matches (i.e. we have found an element with a class of effect and any parent with an id target) 选择器被记录为在 DOM 中匹配,无论 #target 上的悬停状态如何。当#target 上的悬停状态发生变化时,它会简单地碰撞在元素处烘焙的所有选择器 - 这可能会触发整个选择器激活或停用。这样我们就不会在鼠标四处移动时不断测试大量元素。

简而言之,如果它可以随意在 DOM 周围跳跃,那么这些都不起作用。进入/离开 DOM 的元素可能会影响 DOM 完全独立部分中的选择器,因此样式引擎可能会检查整个 DOM 以使该索引保持最新。

部分加载的 DOM

还考虑到我们可以测试元素 before,但不能测试 after(当向后评估时):

h1 + h2
h1 - h2 /* ..? Doesn't exist! */

这是因为当我们从一个“h2”元素开始测试这个特定的选择器时,它后面的 DOM可能实际上还没有被加载。一旦一个元素进入 DOM,无论是因为它刚刚从传入的 HTML 中解析出来,或者它是通过脚本添加的,我们就开始检查它匹配的选择器。这意味着我们不能依赖原始 HTML 中元素之后的任何可用内容,所以这也是任何 DOM 跳跃的块。

总结

目前不可能,也不太可能很快添加,因为它会使 CSS 实现的多个性能特征失效。这并不是说它不会被添加; W3C 确实意识到硬件变得越来越强大,因此总有一点让作者的便利性胜过实现性能的考虑。

因此,将这一点进一步放在问题的上下文中,请查看this fiddle created by @Marvin 以了解当前选择器的可能性。

【讨论】:

  • +1。我已经删除了我的答案,因为您的答案要好得多。我只想用fiddle showing what currently can be selected 扩展您的答案。也许有些读者可能会感兴趣。
  • @Marvin 谢谢 - 我刚刚把它放在最后 :)
  • 非常全面的帖子!正是我想要的!感谢您的努力!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-08
相关资源
最近更新 更多