我可以定位具有更改状态的元素,但我似乎找不到一种方法来根据所讨论的元素的状态找到DOM中的其他元素。
例:
<section> <div>Element 1</div> <div data-status="finished">Element 2</div> <div>Element 3</div> </section> <section> <div>Element 4</div> <div class="blink">Element 5</div> <div>Element 4</div> <div>Element 4</div> <div class="spin">Element 4</div> ... </section>
或者只是渲染具有适当样式的元素的服务器端。
是否有一个CSS选择器,让我指定哪些元素应该基于目标元素的状态被选择?
就像是:
div[data-status~=finished]:affect(.blink,.spin)
那么这样可以让我也只能针对没有CSS的元素呢?
解决方法
How do I select an element based on the state of another element in the page with CSS?
这是否取决于三个条件:
>这些元素的状态是否可以使用简单的选择器来表示,
>是否可以使用组合器在这两个元素之间表达结构关系以形成单个复选择器,以及
>您想要定位的元素是否可以作为生成的复合选择器的主题。
虽然current Selectors standard具有一些有趣且有时潜在的强大功能,但它的设计方式使得它在第2区域(第3号是直接的后果)非常有限。其他一些有限的可能性列在其他答案中,例如通过最基本的使用儿童和兄弟组合器,clever use of dynamic pseudo-classes(实际上与条件#1相关)或a combination of both。
另一方面,问题出在这个问题上,由于这个原因,使用选择器目前无法解决的问题。大多数情况归结为缺乏父选择器和/或以前的兄弟选择器,这两者都可能看起来像微不足道的特征,但具有一定的含义,使得它们难以定义或实现。综上所述:
>是的,这些元素的状态可以使用简单的选择器来表示:div和[data-status〜= finished],后两者的.blink和.spin。
>第一个元素可以用> div [data-status〜= finished],并且两个主题元素可以由部分> .blink和section部分> .spin。问题是,不可能编写一个包含所有这些结构的复杂选择器,因为组合器是单向的,并且没有父组合器与子组合器在第一个部分元素上连接。
>假设前两个问题的答案也是“是”,每个.blink和.spin都可以作为自己的复选框的主题。 (但更多的是在下一节。)
如果您被引导到这个问题,您可能想要解决的问题,如上所述,由于这些限制,无法使用选择器解决问题。
upcoming standard具有一些新功能,将极大地丰富选择器语法,并可能会将其(或CSS)打开(包括CSS),并提供了一些新的可能性,包括可能的示例问题解决方案。所有这些内容将在以下部分中介绍,但首先我将解释每个条件的含义及其与给定示例的关系:
元素状态和元素之间的结构关系
选择器的定义特征是它表示文档树中一个或多个元素的特定结构。这不仅仅是我所做的 – 你可以在informative overview of the Selectors standard中找到这个描述:
A Selector represents a structure. This structure can be used as a condition (e.g. in a CSS rule) that determines which elements a selector matches in the document tree,or as a flat description of the HTML or XML fragment corresponding to that structure.
Selectors may range from simple element names to rich contextual representations.
每个元素由一个或多个简单选择器的序列表示。这个序列被称为复合选择器(我在这里使用来自选择器4的术语,因为它比选择器3中使用的术语更清楚 – 参见this answer中的非详尽的术语列表)。
每个简单的选择器代表元素的一定状态。有一些简单的选择器用于匹配元素的类型(或标签名称),类名称,ID或任意属性。还有伪类,它们代表抽象和在文档树中未直接表示的其他特殊状态,例如元素在其层次结构中的顺序和位置(:nth-child(),:nth-of-type() ),用户交互(:hover,:active,:focus,:checked),超链接的访问(:link,…)等等。
在给定的示例中,具有空格分隔值包含完成的数据状态属性的div元素可以用类型选择器和属性选择器来表示:
div[data-status~=finished]
如果希望选择器仅在指针位于此元素上时才应用,只需抛出:hover伪类:
div[data-status~=finished]:hover
复合选择器通过组合器链接以形成复杂选择器。您可能熟悉的这些组合器,>和〜符号表示由每个复合选择器表示的元素之间的关系。单独使用这两个工具,您可以创建一些非常有趣的结果,如其他答案所示。我在this answer更深入地解释这些基础知识。
在给定的例子中,可以建立以下结构关系:
>第一个section元素是div [data-status〜= finished]的父元素。这使用child combinator >
表示:
section > div[data-status~=finished]
>第二部分紧随第一部分为兄弟姐妹。这使用adjacent sibling combinator +
表示:
section + section
>另外,第二部分是.blink和.spin的父级。这可以使用两个选择器来表示,每个孩子一个:
section + section > .blink,section + section > .spin
为什么需要两个选择器?在这种情况下,主要是因为目前没有subgrouping two compound selectors into one的语法,所以您必须分别表示每个子元素。即将推出的Selectors 4标准引入了一个:matches()伪类,它将提供这种非常的子分组功能:
section + section > :matches(.blink,.spin)
现在,由于复合选择器中的每个复合选择器代表一个元件,因此部分部分表示作为兄弟姐妹的两个元件, div代表一个父母和一个孩子,以及部分> div表示下一个兄弟的孩子,你会认为父组合器和前一个兄弟组合器是相当多余的。那么为什么我们通常会得到这些问题:
> Is there a CSS parent selector?
> Is there a “previous sibling” CSS selector?
而且,更重要的是,为什么这两个问题的答案不是?原因在下一点得到解决:
选择器的主题
选择器的subject始终由最右边的复合选择器表示。例如,选择器部分> div代表三个要素,其中div是主题。你可能会说div是被选中的,或者是针对性的,就像在问题中一样,但是如果你曾经想过是否有适当的术语,它就被称为选择器的主题。
在CSS规则中,样式将应用于由选择器的主题表示的元素。任何子框和伪元素框在适当的情况下继承该元素的样式。 (例外情况是选择器的主体是否包含伪元素,在这种情况下,样式直接应用于伪元素。)
从上一节中选择选择器,我们有以下几点:
>部分的主题> div [data-status〜= finished]是div [data-status〜= finished]。
>部分主题是第二部分选择器。
>截面科目> .blink,section section> .spin分别为.blink和.spin。
>使用:matches(),节中的主题> :matches(.blink,.spin)是:matches(.blink,.spin)。
因此,我们确实需要一个父选择器或前一个同级选择器。但请记住,选择器可以表示复杂的结构。而不是简单地添加与现有组合器相反的新组合器,而是寻找更灵活的解决方案,这正是CSSWG正在做的。
从原来的问题中我们得出以下结论:
Is there a CSS selector that would let me specify which elements should get selected based on target element state?
对此的答案是否定的,将不会。然而,在早期的选择器4(从FPWD到the latest working draft from May 2013)的草稿中,有一个新功能的提议可以让您选择除最右边的复选框之外的任何复合选择器,并将其指定为选择。
一个潜在的解决方案
然而,最近删除了主题指标,有利于:()伪类(反过来为adopted from jQuery)。我推测可能的原因here:
The reason
:has()
is more versatile is because,with the subject selector,it was never made clear in any draft if a single complex selector could have more than one subject selector (since a single complex selector can only ever have one subject) and/or if functional pseudo-classes such as:matches()
accepted the subject selector. But because a pseudo-class is a simple selector,you know that:has()
can be accepted anywhere a pseudo-class is accepted.
所以当你不能改变选择器的主题时,由于它的伪类性质,has()将完全不需要这样做。最好的部分是它完成这一切,然后是一些,而没有从根本上改变选择器语法。
事实上,示例问题可以使用选择器4的:has():
/* Combined with the :matches() example from above */ section:has(> div[data-status~=finished]) + section > div:matches(.blink,.spin)
请注意使用子组合器:它将相对选择器参数作为第一部分的子代。是的,这是世界各地Web开发人员想要多年的难以捉摸的“父选择器”。
因为:has()来自jQuery,你可以使用它今天,虽然:matches()不存在,所以你必须替换为.filter()的调用在此期间:
$('section:has(> div[data-status~=finished]) + section > div') .filter('.blink,.spin') .css('color','red');
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <section> <div>Element 1</div> <div data-status="finished">Element 2</div> <div>Element 3</div> </section> <section> <div>Element 4</div> <div class="blink">Element 5</div> <div>Element 4</div> <div>Element 4</div> <div class="spin">Element 4</div> ... </section>
它是如此多才多艺,它还将允许您不仅“定位不具有相同父项的元素”,而且还允许完全不相关的元素,包括在文档树中的位置可能彼此不同的元素。这将有效地消除上述条件#2,尽管这样做会带来一个重要的警告,我会在一秒钟内得到。例如,如果我们假设所讨论的div元素可能出现在彼此之间没有结构关系的任何地方:has()可以让你做:
:root:has(div[data-status~=finished]) div:matches(.blink,.spin)
…当div [data-status〜= finished]存在于文档树中的任何位置时,会发现div.blink,div.spin,因为文档树中的任何元素必须是文档根元素的后代。
现在,我提到的注意事项是,使用具有以下的任意复杂选择器:has()可能会产生严重的性能影响,这就是为什么父代选择器从未被实现的时间最长,并且主题指标和:has()都没有已经实施后两个特别是有问题的,因为“最右边的复合选择器”定义serves as the basis of mainstream CSS selector engines,这两个特征试图完全挑战它。
这也是为什么:has()暂时从fast profile中排除,因此在CSS中不可用,因为在页面呈现期间需要实时选择器匹配,这是不可否认的性能关键的情况。然而,它仍然可以通过DOM方法querySelector()
,querySelectorAll()
和matches()
(以及任何使用它们的选择器库)访问。
也就是说,CSSWG有plans测试有限的变体:has()(例如,使用单个子组合器或兄弟组合器),看看它们是否可以被实现得足够好以包含在CSS中,这将完全占用绝大多数的使用案例,包括上述第一个例子。
结论
不幸的是,CSS选择器语法今天仍然非常有限;然而,标准的新建议将设置为带来强大的新可能性,而且这些增加的一小部分是基于jQuery已经提供的选择器库的功能。这里希望实现将支持这些新功能用于CSS。