我如何 select 基于页面中另一个元素状态的元素 CSS?
How do I select an element based on the state of another element in the page with CSS?
我有可以反映不同状态的元素,可以由用户触发(:hover
、:focus
等)或由服务器操作(data-status="finished"
、disabled
,等等)。
我可以定位状态已更改的元素,但我似乎无法根据相关元素的状态找到定位 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 一起定位?
在 CSS 的当前状态下,您可以实现的目标非常有限。
简而言之 - 您可以让 CSS 元素对元素的状态变化做出反应,如果它们具有相同的父元素并且是兄弟姐妹,或者是父元素的子元素。
CSS 中元素的状态由 pseudo-classes 处理,它涵盖了浏览器根据用户输入处理的大多数典型交互。
虽然这使您能够处理 DOM 树中元素及其子元素的当前状态的视觉外观,但您仍然无法使其他非子元素做出反应(通过视觉变化样式)到元素的当前状态,因为 CSS 不提供特定类型的 select 或者以灵活的方式做到这一点。
但是,您可以将伪classes 与其他类型的CSS selector 结合起来,并在某些情况下使其工作(我将使用悬停状态,因为这是最明显的):
伪class+相邻兄弟select或
如果 element1
和 element2
在文档树中共享相同的父级并且 element1
紧接在 element2
之前,则
或匹配。
(W3C specification of Adjacent sibling selectors)
div:hover + div {
background:red;
}
Hover on elements:
<div>Element 1</div>
<div>Element 2</div>
<div>Element 3</div>
<div>Element 4</div>
<div>Element 5</div>
伪class+一般兄弟组合
此组合与相邻同级 selector 的工作方式相同,只是被 selected 的元素不需要紧接在第一个元素之后;它可以出现在它之后的任何地方。
div:hover ~ div {
background:red;
}
<div>Element 1</div>
<section>Element 2</section>
<em>Element 3</em>
<div>Element 4</div>
<div>Element 5</div>
Attribute selector + General sibling combinator / Attribute selector + adjacent sibling selector
DOM 个元素的状态通常存储在数据属性中。 CSS 为您提供了一个属性 selector,它允许您根据属性的值应用样式。
以下示例为状态为 »finished« 的元素之后的所有元素设置较低的不透明度:
div[data-status~=finished] ~ div {
opacity: 0.3;
}
<div>Element 1</div>
<div data-status="finished">Element 2</div>
<div>Element 3</div>
<div>Element 4</div>
<div>Element 5</div>
:not()
在某些情况下,:not()
可以帮助您 select 所有其他没有激活状态的元素,但是,非简单的 select 或者还没有CSS3 in :not() 支持,尽管它们在新草案 Selectors Level 4 draft 中被提出。所以目前,你可以不做div:not(.class, .class)
——因为只支持简单的selector(类型selector,通用selector ,属性selector,classselector,IDselector,or伪class).
最后你可以构建一些复杂的 selector 来实现你想做的事情,但通常是静态的,并且可能会在 DOM 结构发生变化时立即停止工作,但对于极端情况,您可能会解决问题。 MDN's pseudo selector list 组合起来会很方便。
不幸的是,在写这篇文章的时候,你仍然需要在CSS之外处理它以获得可靠的解决方案。
由于@easwee 已经发布了一个很好的答案,我不会重复他讨论的任何 pseudo-class 选择器,
我们现在在 css3 中有一个新的伪 class 是 :target。
The :target
pseudo selector in CSS matches when the hash in the
URL and the id of an element are the same.
(:target 的具体用途是设置目标元素的样式,该元素当前在视口顶部可见)
因此,当与另一个伪 classes 或兄弟选择器一起使用时,这实际上可以根据用户交互(具体单击)被(误)用于更改其他元素样式。
例如:parent 的兄弟姐妹的目标 child。
:target section div[data-status=finished] {
color: red;
}
a,
a:visited {
text-decoration: none;
color: #000;
}
section {
border: 1px solid grey;
}
<nav id='nav'>
<h4>This is Navigation section</h4>
<section>
sibling
<div><a href='#nav'>(child)click me to target child of sibling of parent</a>
</div>
</section>
<section>
sibling
<div data-status="finished">(child)I am child of parent of sibling</div>
</section>
</nav>
请注意,在引入 :target
之前,无法为 parent 元素或 html 层次结构中的任何其他元素设置样式。它仍然是新的,做这样的事情(根据点击另一个元素选择另一个元素)并不是 :target
设计的原因。
缺点:
使用 target 定位元素,要求不要在单个页面中使用太多,否则会使您在整个页面中随意导航。
元素的目标样式将保留在其上,直到目标保持不变。
你可以玩这个fiddle
规范问题的一般答案
How do I select an element based on the state of another element in the page with CSS?
是它恰好取决于三个条件:
- 是否可以使用简单的选择器来表示这些元素的状态,
- 是否可以使用组合子来表达这两个元素之间的结构关系,以形成一个单个复杂选择器,以及
- 您要定位的元素是否可以成为生成的复杂选择器的主题。
而 current Selectors standard has some interesting and sometimes potentially powerful features, the way it is designed makes it extremely limited in area #2 (with #3 being a direct consequence). Some of these limited possibilities are enumerated in other answers, e.g. through the most basic use of child and sibling combinators, (which actually relates to condition #1), or .
另一方面,由于这个原因,无法使用选择器中当前可用的方法解决问题中给出的问题。大部分原因归结为缺少 parent 选择器 and/or 之前的同级选择器,这两个功能看起来微不足道,但具有某些含义,使它们难以定义或很好地实现。总结:
是的,这些元素的状态可以用简单的选择器来表示:div
和[data-status~=finished]
代表前者,.blink
和.spin
对于后两者。
第一个元素可以用section > div[data-status~=finished]
表示,两个主题元素分别可以用section + section > .blink
和section + section > .spin
表示。问题是不可能编写包含所有这些结构的复杂选择器,因为组合器是 one-way,并且没有 parent 对应 child 组合器在第一个 section
元素。
假设前两题的答案也是"yes",.blink
和.spin
都可以作为其[=203=的主语]own 复杂选择器。 (下一节会详细介绍。)
如果您被定向到这个问题,很可能您要解决的问题(如上面给出的问题)由于这些限制而无法使用选择器解决。
upcoming standard 拥有一些新功能,这些功能将极大地丰富选择器语法并可能将其(和 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.
每个元素都由一个或多个简单选择器的序列表示。这个序列被称为复合选择器(我在这里使用的是 Selectors 4 中的术语,因为它比 Selectors 3 中使用的术语更清晰——参见 this answer 的 non-exhaustive 术语列表)。
每个简单的选择器代表一个元素的特定状态。有一些简单的选择器用于匹配元素的类型(或标记名称)、class 名称、ID 或任意属性。还有 pseudo-classes,表示抽象和其他未在文档树中直接表示的特殊状态,例如元素在其层次结构中的顺序和位置(:nth-child()
、:nth-of-type()
),用户交互(:hover
、:active
、:focus
、:checked
)、超链接的访问量(:link
、:visited
)等等.
在给定的示例中,具有 data-status
属性的 div
元素的 space-delimited 值包含 finished
可以用类型选择器和属性选择器表示:
div[data-status~=finished]
如果您希望选择器仅在指针位于该元素上时应用,只需输入 :hover
pseudo-class:
div[data-status~=finished]:hover
复合选择器通过组合器链接以形成复合选择器。这些组合符,即您可能熟悉的 >
、+
和 ~
符号,表达了每个复合选择器所表示的元素之间的关系。仅使用这两个工具,您就已经能够创建一些非常有趣的结果,如此处的其他答案所示。我在 .
中更深入地解释了这些基础知识
在给出的例子中,可以建立如下结构关系:
第一个 section
元素是 div[data-status~=finished]
的 parent。这是使用 child combinator >
:
表示的
section > div[data-status~=finished]
第二个 section
紧跟在第一个之后作为其兄弟。这是使用 adjacent sibling combinator +
:
表示的
section + section
另外,第二个section
是.blink
和.spin
的parent。这可以使用两个选择器来表示,每个选择器一个 child:
section + section > .blink,
section + section > .spin
为什么需要两个选择器?在这种情况下,主要是因为目前没有 subgrouping two compound selectors into one 的语法,因此您必须分别表示每个 child 元素。即将推出的 Selectors 4 标准引入了:matches()
pseudo-class 将提供这种分组功能:
section + section > :matches(.blink, .spin)
现在,由于复合选择器中的每个复合选择器代表一个元素,因此 section + section
代表两个兄弟元素,section > div
代表一个 parent 和一个 child,而section + section > div
表示next-sibling的child,你会认为parent组合子和previous-sibling组合子是相当多余的。那么为什么我们经常会遇到这些问题:
- Is there a CSS parent selector?
- Is there a "previous sibling" CSS selector?
而且,更重要的是,为什么这两个问题的答案都是否?原因在下一点解决:
选择器的主题
选择器的subject总是由最右边的复合选择器表示。例如,选择器section + section > div
代表三个元素,其中div
是主语。您可能会说 div
是 selected,或 targeted,如问题所示,但如果您曾经想过是否有是一个专有名词,它被称为选择器的主题。
在 CSS 规则中,样式应用于选择器主题所代表的元素。任何 child 框和 pseudo-element 框在适当的地方继承此元素的样式。 (例外情况是,如果选择器的主题包含 pseudo-element,在这种情况下,样式仅直接应用于 pseudo-element。)
采用上一节中的选择器,我们有以下内容:
section > div[data-status~=finished]
的主题是div[data-status~=finished]
。
section + section
的主题是 second section
选择器。
section + section > .blink, section + section > .spin
的主题分别是.blink
和.spin
。
- 使用
:matches()
,section + section > :matches(.blink, .spin)
的主语是:matches(.blink, .spin)
。
因此,我们似乎确实需要 parent 选择器或 previous-sibling 选择器。但请记住,选择器已经可以表示复杂的结构。与其简单地添加与现有组合器相反的新组合器,不如寻找更灵活的解决方案,这正是 CSSWG 一直在做的事情。
这使我们从原始问题中得出以下结论:
Is there a CSS selector that would let me specify which elements should get selected based on target element state?
这个问题的答案是否定的,并且将保持否。然而,在 Selectors 4 的早期草稿中(来自 FPWD up to the latest working draft from May 2013),有一项新功能的提议,可以让您选择除最右边的那个之外的任何复合选择器,并将其指定为主题选择器。
一个潜在的解决方案
但是,主题指标最近被删除,取而代之的是 :has()
pseudo-class(这又是 adopted from jQuery). I speculate on a likely reason :
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.
因此,虽然您无法更改选择器的主题,但由于 pseudo-class 的性质,:has()
将完全取消这样做的需要。最好的部分是它做到了这一点——然后是一些——所有这些都没有从根本上改变选择器语法。
事实上,示例问题 可以使用 Selectors 4 的 :has()
:
来解决
/* Combined with the :matches() example from above */
section:has(> div[data-status~=finished]) + section > div:matches(.blink, .spin)
注意 child 组合子的使用:这将相对选择器参数的范围限定为第一个 section
的 children。是的,这就是全世界的 Web 开发人员多年来一直想要的难以捉摸的 "parent selector"。
并且由于 :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>
它用途广泛,不仅可以让您 "target elements that don't have the same parent",还可以让您处理完全不相关的元素,包括在文档树中的位置可能互不相同的元素。这将 有效地消除 上面的条件 #2,尽管这样做有一个重要的警告,我稍后会谈到。例如,如果我们假设所讨论的 div
元素可能出现在彼此之间没有结构关系的任何地方,则 :has()
允许您执行以下操作:
:root:has(div[data-status~=finished]) div:matches(.blink, .spin)
... 当 div[data-status~=finished]
存在 文档树中的任何位置时 ... 找到 div.blink, div.spin
,因为文档树中的任何元素都必须是文档根元素。
现在,我提到的警告是,使用带有 :has()
的任意复杂选择器可能会对性能产生严重影响,这就是为什么最长的时间 parent 选择器从未被实现,并且两者主题指标和 :has()
尚未实施。后两者尤其有问题,因为 "rightmost compound selector" 定义 serves as the basis of mainstream CSS selector engines,而这两个特征试图完全挑战它。
这也是为什么 :has()
暂时被排除在 fast profile and may therefore not be usable in CSS, as it requires real-time selector matching during page rendering, a situation that is undeniably performance-critical. It will still be accessible through the DOM methods querySelector()
, querySelectorAll()
and matches()
(以及碰巧使用它们的任何选择器库)之外的原因。
也就是说,CSSWG 有 plans 来测试 :has()
的有限变体(例如 wih 单个 child 组合器或兄弟组合器)以查看它们是否可以很好地实现以包含在 CSS 中,这将满足 大量 大多数用例, 包括上面第一个例子
结论
不幸的是,CSS 选择器语法在今天仍然非常有限;然而,该标准的新提案将带来强大的新可能性,其中一些新增功能是基于 jQuery 等选择器库已经提供的功能。希望实现将支持这些新功能,以便在 CSS.
中使用
我有可以反映不同状态的元素,可以由用户触发(:hover
、:focus
等)或由服务器操作(data-status="finished"
、disabled
,等等)。
我可以定位状态已更改的元素,但我似乎无法根据相关元素的状态找到定位 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 一起定位?
在 CSS 的当前状态下,您可以实现的目标非常有限。
简而言之 - 您可以让 CSS 元素对元素的状态变化做出反应,如果它们具有相同的父元素并且是兄弟姐妹,或者是父元素的子元素。
CSS 中元素的状态由 pseudo-classes 处理,它涵盖了浏览器根据用户输入处理的大多数典型交互。
虽然这使您能够处理 DOM 树中元素及其子元素的当前状态的视觉外观,但您仍然无法使其他非子元素做出反应(通过视觉变化样式)到元素的当前状态,因为 CSS 不提供特定类型的 select 或者以灵活的方式做到这一点。
但是,您可以将伪classes 与其他类型的CSS selector 结合起来,并在某些情况下使其工作(我将使用悬停状态,因为这是最明显的):
伪class+相邻兄弟select或
如果 element1
和 element2
在文档树中共享相同的父级并且 element1
紧接在 element2
之前,则
或匹配。 (W3C specification of Adjacent sibling selectors)
div:hover + div {
background:red;
}
Hover on elements:
<div>Element 1</div>
<div>Element 2</div>
<div>Element 3</div>
<div>Element 4</div>
<div>Element 5</div>
伪class+一般兄弟组合
此组合与相邻同级 selector 的工作方式相同,只是被 selected 的元素不需要紧接在第一个元素之后;它可以出现在它之后的任何地方。
div:hover ~ div {
background:red;
}
<div>Element 1</div>
<section>Element 2</section>
<em>Element 3</em>
<div>Element 4</div>
<div>Element 5</div>
Attribute selector + General sibling combinator / Attribute selector + adjacent sibling selector
DOM 个元素的状态通常存储在数据属性中。 CSS 为您提供了一个属性 selector,它允许您根据属性的值应用样式。
以下示例为状态为 »finished« 的元素之后的所有元素设置较低的不透明度:
div[data-status~=finished] ~ div {
opacity: 0.3;
}
<div>Element 1</div>
<div data-status="finished">Element 2</div>
<div>Element 3</div>
<div>Element 4</div>
<div>Element 5</div>
:not()
在某些情况下,:not()
可以帮助您 select 所有其他没有激活状态的元素,但是,非简单的 select 或者还没有CSS3 in :not() 支持,尽管它们在新草案 Selectors Level 4 draft 中被提出。所以目前,你可以不做div:not(.class, .class)
——因为只支持简单的selector(类型selector,通用selector ,属性selector,classselector,IDselector,or伪class).
最后你可以构建一些复杂的 selector 来实现你想做的事情,但通常是静态的,并且可能会在 DOM 结构发生变化时立即停止工作,但对于极端情况,您可能会解决问题。 MDN's pseudo selector list 组合起来会很方便。
不幸的是,在写这篇文章的时候,你仍然需要在CSS之外处理它以获得可靠的解决方案。
由于@easwee 已经发布了一个很好的答案,我不会重复他讨论的任何 pseudo-class 选择器,
我们现在在 css3 中有一个新的伪 class 是 :target。
The
:target
pseudo selector in CSS matches when the hash in the URL and the id of an element are the same.
(:target 的具体用途是设置目标元素的样式,该元素当前在视口顶部可见)
因此,当与另一个伪 classes 或兄弟选择器一起使用时,这实际上可以根据用户交互(具体单击)被(误)用于更改其他元素样式。
例如:parent 的兄弟姐妹的目标 child。
:target section div[data-status=finished] {
color: red;
}
a,
a:visited {
text-decoration: none;
color: #000;
}
section {
border: 1px solid grey;
}
<nav id='nav'>
<h4>This is Navigation section</h4>
<section>
sibling
<div><a href='#nav'>(child)click me to target child of sibling of parent</a>
</div>
</section>
<section>
sibling
<div data-status="finished">(child)I am child of parent of sibling</div>
</section>
</nav>
请注意,在引入
:target
之前,无法为 parent 元素或 html 层次结构中的任何其他元素设置样式。它仍然是新的,做这样的事情(根据点击另一个元素选择另一个元素)并不是 :target
设计的原因。
缺点:
使用 target 定位元素,要求不要在单个页面中使用太多,否则会使您在整个页面中随意导航。
元素的目标样式将保留在其上,直到目标保持不变。
你可以玩这个fiddle
规范问题的一般答案
How do I select an element based on the state of another element in the page with CSS?
是它恰好取决于三个条件:
- 是否可以使用简单的选择器来表示这些元素的状态,
- 是否可以使用组合子来表达这两个元素之间的结构关系,以形成一个单个复杂选择器,以及
- 您要定位的元素是否可以成为生成的复杂选择器的主题。
而 current Selectors standard has some interesting and sometimes potentially powerful features, the way it is designed makes it extremely limited in area #2 (with #3 being a direct consequence). Some of these limited possibilities are enumerated in other answers, e.g. through the most basic use of child and sibling combinators,
另一方面,由于这个原因,无法使用选择器中当前可用的方法解决问题中给出的问题。大部分原因归结为缺少 parent 选择器 and/or 之前的同级选择器,这两个功能看起来微不足道,但具有某些含义,使它们难以定义或很好地实现。总结:
是的,这些元素的状态可以用简单的选择器来表示:
div
和[data-status~=finished]
代表前者,.blink
和.spin
对于后两者。第一个元素可以用
section > div[data-status~=finished]
表示,两个主题元素分别可以用section + section > .blink
和section + section > .spin
表示。问题是不可能编写包含所有这些结构的复杂选择器,因为组合器是 one-way,并且没有 parent 对应 child 组合器在第一个section
元素。假设前两题的答案也是"yes",
.blink
和.spin
都可以作为其[=203=的主语]own 复杂选择器。 (下一节会详细介绍。)
如果您被定向到这个问题,很可能您要解决的问题(如上面给出的问题)由于这些限制而无法使用选择器解决。
upcoming standard 拥有一些新功能,这些功能将极大地丰富选择器语法并可能将其(和 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.
每个元素都由一个或多个简单选择器的序列表示。这个序列被称为复合选择器(我在这里使用的是 Selectors 4 中的术语,因为它比 Selectors 3 中使用的术语更清晰——参见 this answer 的 non-exhaustive 术语列表)。
每个简单的选择器代表一个元素的特定状态。有一些简单的选择器用于匹配元素的类型(或标记名称)、class 名称、ID 或任意属性。还有 pseudo-classes,表示抽象和其他未在文档树中直接表示的特殊状态,例如元素在其层次结构中的顺序和位置(:nth-child()
、:nth-of-type()
),用户交互(:hover
、:active
、:focus
、:checked
)、超链接的访问量(:link
、:visited
)等等.
在给定的示例中,具有 data-status
属性的 div
元素的 space-delimited 值包含 finished
可以用类型选择器和属性选择器表示:
div[data-status~=finished]
如果您希望选择器仅在指针位于该元素上时应用,只需输入 :hover
pseudo-class:
div[data-status~=finished]:hover
复合选择器通过组合器链接以形成复合选择器。这些组合符,即您可能熟悉的 >
、+
和 ~
符号,表达了每个复合选择器所表示的元素之间的关系。仅使用这两个工具,您就已经能够创建一些非常有趣的结果,如此处的其他答案所示。我在
在给出的例子中,可以建立如下结构关系:
第一个
表示的section
元素是div[data-status~=finished]
的 parent。这是使用 child combinator>
:section > div[data-status~=finished]
第二个
表示的section
紧跟在第一个之后作为其兄弟。这是使用 adjacent sibling combinator+
:section + section
另外,第二个
section
是.blink
和.spin
的parent。这可以使用两个选择器来表示,每个选择器一个 child:section + section > .blink, section + section > .spin
为什么需要两个选择器?在这种情况下,主要是因为目前没有 subgrouping two compound selectors into one 的语法,因此您必须分别表示每个 child 元素。即将推出的 Selectors 4 标准引入了
:matches()
pseudo-class 将提供这种分组功能:section + section > :matches(.blink, .spin)
现在,由于复合选择器中的每个复合选择器代表一个元素,因此 section + section
代表两个兄弟元素,section > div
代表一个 parent 和一个 child,而section + section > div
表示next-sibling的child,你会认为parent组合子和previous-sibling组合子是相当多余的。那么为什么我们经常会遇到这些问题:
- Is there a CSS parent selector?
- Is there a "previous sibling" CSS selector?
而且,更重要的是,为什么这两个问题的答案都是否?原因在下一点解决:
选择器的主题
选择器的subject总是由最右边的复合选择器表示。例如,选择器section + section > div
代表三个元素,其中div
是主语。您可能会说 div
是 selected,或 targeted,如问题所示,但如果您曾经想过是否有是一个专有名词,它被称为选择器的主题。
在 CSS 规则中,样式应用于选择器主题所代表的元素。任何 child 框和 pseudo-element 框在适当的地方继承此元素的样式。 (例外情况是,如果选择器的主题包含 pseudo-element,在这种情况下,样式仅直接应用于 pseudo-element。)
采用上一节中的选择器,我们有以下内容:
section > div[data-status~=finished]
的主题是div[data-status~=finished]
。section + section
的主题是 secondsection
选择器。section + section > .blink, section + section > .spin
的主题分别是.blink
和.spin
。- 使用
:matches()
,section + section > :matches(.blink, .spin)
的主语是:matches(.blink, .spin)
。
因此,我们似乎确实需要 parent 选择器或 previous-sibling 选择器。但请记住,选择器已经可以表示复杂的结构。与其简单地添加与现有组合器相反的新组合器,不如寻找更灵活的解决方案,这正是 CSSWG 一直在做的事情。
这使我们从原始问题中得出以下结论:
Is there a CSS selector that would let me specify which elements should get selected based on target element state?
这个问题的答案是否定的,并且将保持否。然而,在 Selectors 4 的早期草稿中(来自 FPWD up to the latest working draft from May 2013),有一项新功能的提议,可以让您选择除最右边的那个之外的任何复合选择器,并将其指定为主题选择器。
一个潜在的解决方案
但是,主题指标最近被删除,取而代之的是 :has()
pseudo-class(这又是 adopted from jQuery). I speculate on a likely reason
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.
因此,虽然您无法更改选择器的主题,但由于 pseudo-class 的性质,:has()
将完全取消这样做的需要。最好的部分是它做到了这一点——然后是一些——所有这些都没有从根本上改变选择器语法。
事实上,示例问题 可以使用 Selectors 4 的 :has()
:
/* Combined with the :matches() example from above */
section:has(> div[data-status~=finished]) + section > div:matches(.blink, .spin)
注意 child 组合子的使用:这将相对选择器参数的范围限定为第一个 section
的 children。是的,这就是全世界的 Web 开发人员多年来一直想要的难以捉摸的 "parent selector"。
并且由于 :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>
它用途广泛,不仅可以让您 "target elements that don't have the same parent",还可以让您处理完全不相关的元素,包括在文档树中的位置可能互不相同的元素。这将 有效地消除 上面的条件 #2,尽管这样做有一个重要的警告,我稍后会谈到。例如,如果我们假设所讨论的 div
元素可能出现在彼此之间没有结构关系的任何地方,则 :has()
允许您执行以下操作:
:root:has(div[data-status~=finished]) div:matches(.blink, .spin)
... 当 ... 找到 现在,我提到的警告是,使用带有 这也是为什么 也就是说,CSSWG 有 plans 来测试 不幸的是,CSS 选择器语法在今天仍然非常有限;然而,该标准的新提案将带来强大的新可能性,其中一些新增功能是基于 jQuery 等选择器库已经提供的功能。希望实现将支持这些新功能,以便在 CSS.div[data-status~=finished]
存在 文档树中的任何位置时 div.blink, div.spin
,因为文档树中的任何元素都必须是文档根元素。:has()
的任意复杂选择器可能会对性能产生严重影响,这就是为什么最长的时间 parent 选择器从未被实现,并且两者主题指标和 :has()
尚未实施。后两者尤其有问题,因为 "rightmost compound selector" 定义 serves as the basis of mainstream CSS selector engines,而这两个特征试图完全挑战它。:has()
暂时被排除在 fast profile and may therefore not be usable in CSS, as it requires real-time selector matching during page rendering, a situation that is undeniably performance-critical. It will still be accessible through the DOM methods querySelector()
, querySelectorAll()
and matches()
(以及碰巧使用它们的任何选择器库)之外的原因。:has()
的有限变体(例如 wih 单个 child 组合器或兄弟组合器)以查看它们是否可以很好地实现以包含在 CSS 中,这将满足 大量 大多数用例, 包括上面第一个例子结论