如何使用 CSS 根据页面中另一个元素的状态选择一个元素? [英] How do I select an element based on the state of another element in the page with CSS?

查看:24
本文介绍了如何使用 CSS 根据页面中另一个元素的状态选择一个元素?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有可以反映不同状态的元素,可以由用户触发(:hover:focus 等)或由服务器操作(data-status="finished"disabled 等).

I have elements that can reflect different states, either triggered by the user (:hover, :focus, etc.) or manipulated by the server (data-status="finished", disabled, etc.).

我可以定位状态发生变化的元素,但我似乎无法根据相关元素的状态找到定位 DOM 中其他元素的方法.

I can target the element that has a changed state, but I can't seem to find a way to target other elements in the DOM based on the state of the element in question.

示例:

<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>

或者只是在服务器端渲染具有适当样式的元素.

or just render the elements with proper styles server-side.

是否有一个 CSS 选择器可以让我根据目标元素的状态指定应该选择哪些元素?

Is there a CSS selector that would let me specify which elements should get selected based on the target element's state?

类似于:

div[data-status~=finished]:affect(.blink, .spin)

这是否允许我也仅使用 CSS 来定位不具有相同父元素的元素?

that would allow me to also target elements that don't have the same parent with CSS only?

推荐答案

规范问题的一般答案

如何使用 CSS 根据页面中另一个元素的状态选择一个元素?

How do I select an element based on the state of another element in the page with CSS?

是它完全取决于三个条件:

is that it depends on exactly three conditions:

  1. 是否可以使用简单的选择器来表示这些元素的状态,
  2. 是否可以使用组合子来表达这两个元素之间的结构关系以形成单个复杂选择器,以及
  3. 您要定位的元素是否可以成为结果复杂选择器的主题.

虽然 当前选择器标准 有一些有趣且有时可能很强大的功能,但是它的设计使其在区域#2 中受到极大限制(#3 是直接后果).在其他答案中列举了其中一些有限的可能性,例如通过最基本的使用子和兄弟组合器,巧妙使用动态伪类(实际上与条件#1 相关),或两者的结合.

While the 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, clever use of dynamic pseudo-classes (which actually relates to condition #1), or a combination of both.

另一方面,由于这个原因,使用选择器中当前可用的内容无法解决问题中给出的问题.这主要归结为缺少父选择器和/或前一个兄弟选择器,这两个功能看起来都是微不足道的,但具有某些含义,使它们难以定义或很好地实现.总结:

The problem given in the question, on the other hand, cannot be solved using what is currently available in Selectors for this reason. Most of this boils down to the lack of either a parent selector and/or a previous sibling selector, both of which may seem like trivial features, but have certain implications that make them difficult to define or implement well. In summary:

  1. 是的,这些元素的状态可以使用简单的选择器来表示:div[data-status~=finished] 表示前者,而 <后两者的代码>.blink 和 .spin.

  1. Yes, the state of these elements can be represented using simple selectors: div and [data-status~=finished] for the former, and .blink and .spin for the latter two.

第一个元素可以用section >表示div[data-status~=finished],两个主题元素可以用section+section>表示.blinksection + section >.spin 分别.问题是不可能编写一个包含所有这些结构的复杂选择器,因为组合器是单向的,并且没有与子组合器对应的父组合来在第一个 section 元素连接它们.

The first element can be represented by section > div[data-status~=finished], and the two subject elements can be represented by section + section > .blink and section + section > .spin respectively. The problem is that it's not possible to write a complex selector incorporating all of these structures, because combinators are one-way, and there is no parent counterpart to the child combinator to join them at the first section element.

假设前两个问题的答案也是是",则.blink.spin 都可以成为其own 复杂的选择器.(但下一节会详细介绍.)

Assuming the answer to the first two questions is also "yes", each of .blink and .spin can be made the subject of its own complex selector. (But more on that in the next section.)

如果您已被引导到这个问题,那么很可能您要解决的问题(如上面给出的问题)由于这些限制而无法使用选择器解决.

If you've been directed to this question, chances are the problem you're trying to solve, like the one given above, cannot be solved with Selectors due to these limitations.

即将出台的标准拥有一些新功能,这些功能将极大地丰富选择器语法并可能开放它(和 CSS)提供了许多新的可能性,包括示例问题的可能解决方案.所有这些内容将在以下部分中介绍,但首先我将解释每个条件的含义以及它与给定示例的关系:

The upcoming standard boasts some new features that will greatly enrich selector syntax and potentially open it (and CSS) up to a host of new possibilities, including a possible solution to the example problem. All of these things will be covered in the following sections, but first I'll explain what each condition means and how it relates to the given example:

选择器的定义特征是它表示文档树中一个或多个元素的特定结构.这不仅仅是我编造的——你实际上可以在 信息概述中找到这个描述选择器标准:

The defining characteristic of a selector is that it represents a certain structure of one or more elements in the document tree. This isn't just something I made up — you can actually find this description in the informative overview of the Selectors standard:

选择器代表一个结构.此结构可用作条件(例如在 CSS 规则中),用于确定选择器在文档树中匹配哪些元素,或用作与该结构对应的 HTML 或 XML 片段的平面描述.

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 中使用的要清楚得多——参见 此答案 用于非详尽的术语列表).

Each element is represented by a sequence of one or more simple selectors. This sequence is known as a compound selector (I'm using terminology from Selectors 4 here as it is much clearer than what is used in Selectors 3 — see this answer for a non-exhaustive list of terms).

每个简单的选择器代表一个元素的特定状态.有一些简单的选择器用于匹配元素的类型(或标签名)、类名、ID 或任意属性.还有伪类,它们表示抽象和其他在文档树中没有直接表示的特殊状态,例如元素在其层次结构中的顺序和位置(:nth-child(), :nth-of-type())、用户交互(:hover:active:focus:checked)、超链接的访问度(:link:visited)等等.

Each simple selector represents a certain state of an element. There are simple selectors for matching the type (or tag name) of an element, a class name, an ID, or an arbitrary attribute. There are also pseudo-classes, which represent abstractions and other special states not directly represented within the document tree, such as the order and position of an element in its hierarchy (:nth-child(), :nth-of-type()), user interactions (:hover, :active, :focus, :checked), the visitedness of a hyperlink (:link, :visited), and much more.

在给定的示例中,带有 data-status 属性的 div 元素可以用空格分隔的值包含 finished 来表示类型选择器和属性选择器:

In the given example, the div element with a data-status attribute whose space-delimited value contains finished can be represented with a type selector and an attribute selector:

div[data-status~=finished]

如果您希望选择器仅在指针位于该元素上时应用,只需放入一个 :hover 伪类:

If you want the selector to apply only when the pointer is over this element, simply throw in a :hover pseudo-class:

div[data-status~=finished]:hover

复合选择器通过组合器链接形成复合选择器.这些组合子,你可能熟悉的 >+~ 符号,表达了每个复合选择器所代表的元素之间的关系.仅使用这两个工具,您就已经能够创建一些非常有趣的结果,如此处的其他答案所示.我在 this 中更深入地解释了这些基础知识回答.

Compound selectors are linked via combinators to form complex selectors. These combinators, the >, + and ~ symbols that you may be familiar with, express a relationship between the elements represented by each compound selector. With these two tools alone, you're already able to create some very interesting results as shown in the other answers here. I explain these basics in even further depth in this answer.

在给定的例子中,可以建立以下结构关系:

In the given example, the following structural relationships can be established:

  • The first section element is the parent of div[data-status~=finished]. This is represented using the child combinator >:

section > div[data-status~=finished]

  • 第二个 section 紧跟在第一个之后,作为它的兄弟.这是使用相邻兄弟组合子+:

  • The second section immediately follows the first one as its sibling. This is represented using the adjacent sibling combinator +:

    section + section
    

  • 此外,第二个section.blink.spin 的父级.这可以使用两个选择器来表示,每个孩子一个:

  • Additionally, the second section is the parent of both .blink and .spin. This can be represented using two selectors, one for each child:

    section + section > .blink, 
    section + section > .spin
    

    为什么需要两个选择器?在这种情况下,主要是因为 将两个复合选择器组合成一个,因此您必须分别表示每个子元素.即将推出的 Selectors 4 标准引入了一个 :matches() 伪类,它将提供这种非常子分组的功能:

    Why are two selectors required? In this case it's mainly because there is currently no syntax for subgrouping two compound selectors into one, so you will have to represent each child element separately. The upcoming Selectors 4 standard introduces a :matches() pseudo-class that will provide this very subgrouping functionality:

    section + section > :matches(.blink, .spin)
    

  • 现在,由于复合选择器中的每个复合选择器都代表一个元素,因此 section + section 代表两个兄弟元素,section >div 代表父子,section + section >div 代表下一个兄弟的孩子,你会认为父组合器和前一个兄弟组合器是非常多余的.那么为什么我们经常会遇到这些问题:

    Now, since every compound selector in a complex selector represents one element, and thus section + section represents two elements that are siblings, section > div represents a parent and a child, and section + section > div represents a child of a next-sibling, you would think that a parent combinator and a previous-sibling combinator are quite redundant. So why do we commonly get these questions:

    而且,更重要的是,为什么这两个问题的答案都是?原因在下一点说明:

    And, more importantly, why is the answer to both of these questions no? The reason is addressed in the next point:

    选择器的主题总是由最右边的复合选择器表示.例如,选择器 section + section >div 代表三个元素,其中div 是主语.您可能会说 divselectedtargeted,如问题中所述,但是如果您想知道是否有适当的术语,它被称为选择器的主题.

    The subject of a selector is always represented by the rightmost compound selector. For example, the selector section + section > div represents three elements, of which div is the subject. You might say that the div is selected, or targeted, as in the question, but if you've ever wondered if there was a proper term, it's known as the subject of the selector.

    在 CSS 规则中,样式应用于由选择器的主题表示的元素.在适当的情况下,任何子框和伪元素框都从该元素继承样式.(例外情况是选择器的主题包含伪元素,在这种情况下,样式仅直接应用于伪元素.)

    In a CSS rule, styles are applied to the element represented by the subject of the selector. Any child boxes and pseudo-element boxes inherit the styles from this element where appropriate. (The exception is if the subject of the selector includes a pseudo-element, in which case the styles are applied directly to the pseudo-element only.)

    采用上一节中的选择器,我们有以下内容:

    Taking the selectors from the previous section, we have the following:

    • 部分的主题>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).
    • The subject of section > div[data-status~=finished] is div[data-status~=finished].
    • The subject of section + section is the second section selector.
    • The subjects of section + section > .blink, section + section > .spin are .blink and .spin respectively.
    • Using :matches(), the subject of section + section > :matches(.blink, .spin) is :matches(.blink, .spin).

    因此看起来我们确实需要一个父选择器或一个前兄弟选择器.但请记住,选择器已经可以表示复杂的结构.与其简单地添加与现有组合器相反的新组合器,不如寻求一种更灵活的解决方案,而这正是 CSSWG 一直在做的事情.

    It might seem therefore that we do need a parent selector or a previous-sibling selector. But remember that selectors can already represent complex structures. Instead of simply adding new combinators that work opposite of existing ones, it makes sense to seek out a more flexible solution, and that is exactly what the CSSWG has been doing.

    这使我们从原始问题中得出以下结论:

    Which brings us to the following from the original question:

    是否有一个 CSS 选择器可以让我根据目标元素状态指定应该选择哪些元素?

    Is there a CSS selector that would let me specify which elements should get selected based on target element state?

    对此的答案是否定的,并且仍然不会.但是,在早期的 Selectors 4 草案中(来自 FPWD 直到 2013 年 5 月的最新工作草案),有一个提案新功能可让您选择最右边的以外的任何复合选择器,并将其指定为选择器的主题.

    The answer to this is no, and will remain no. However, in the earlier drafts of Selectors 4 (from the FPWD up to the latest working draft from May 2013), there was a proposal for a new feature that would let you pick any of the compound selectors other than the rightmost one, and designate that as the subject of the selector.

    然而,最近删除了主题指示符,取而代之的是 :has() 伪类(反过来是 从jQuery 采用).我在此处推测可能的原因:

    However, the subject indicator was recently removed in favor of the :has() pseudo-class (that was in turn adopted from jQuery). I speculate on a likely reason here:

    :has() 更通用的原因是,对于主题选择器,如果一个复杂的选择器可以有多个主题选择器(因为单个复杂选择器只能有一个主题)和/或如果功能伪类如 :matches() 接受主题选择器.但是因为伪类是一个简单的选择器,你知道 :has() 可以在任何接受伪类的地方被接受.

    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() 将完全取消这样做的需要,因为它是伪类的性质.最好的部分是它做到了这一点——然后一些——所有这些都没有从根本上改变选择器的语法.

    So while you cannot change the subject of a selector, :has() will completely write off the need to do so, due to its pseudo-class nature. And the best part is that it does this — and then some — all without fundamentally changing selector syntax.

    事实上,示例问题可以解决使用选择器 4 的 :has():

    In fact, the example problem can be solved using Selectors 4's :has():

    /* Combined with the :matches() example from above */
    section:has(> div[data-status~=finished]) + section > div:matches(.blink, .spin)
    

    注意子组合器的使用:这将相对选择器参数的范围限定为第一个 section 的子节点.是的,这就是世界各地的 Web 开发人员多年来一直想要的难以捉摸的父选择器".

    Notice the use of a child combinator: this scopes the relative selector argument to just children of the first section. Yes, this is the elusive "parent selector" that Web developers the world over have been wanting for years.

    并且由于 :has() 来自 jQuery,您可以今天使用它,尽管 :matches() 尚不存在所以你必须同时调用 .filter() 来替换它:

    And since :has() comes from jQuery, you can use it today, although :matches() doesn't exist yet so you'll have to replace that with a call to .filter() in the meantime:

    $('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() 允许您这样做:

    It's so versatile, that it will also allow you to not only "target elements that don't have the same parent", but also elements that are completely unrelated, including elements whose positions in the document tree may vary irrespective of one another. This will effectively eliminate condition #2 above, although doing so comes with a major caveat which I'll get to in a second. For example, if we assume that the div elements in question may appear anywhere with no structural relation to one another, :has() allows you to do:

    :root:has(div[data-status~=finished]) div:matches(.blink, .spin)
    

    ... 当 div[data-status~=finished] 存在于文档树中的任意位置 时,它会找到 div.blink, div.spinem>,因为文档树中的任何元素都必须是文档根元素的后代.

    ... which finds div.blink, div.spin when div[data-status~=finished] exists anywhere in the document tree, since any element in the document tree must be a descendant of the document root element.

    现在,我提到的警告是,将任意复杂选择器与 :has() 一起使用可能会对性能产生严重影响,这就是为什么在很长一段时间内从未实现父选择器的原因,并且两者都主题指示器和 :has() 尚未实现.后两者尤其有问题,因为最右边的复合选择器"定义 作为主流 CSS 选择器引擎的基础,这两个特性试图共同挑战它.

    Now, the caveat that I mentioned, is that using arbitrary complex selectors with :has() can have serious performance implications, which is why for the longest time parent selectors were never implemented, and both the subject indicator and :has() have not been implemented yet. The latter two in particular are problematic because the "rightmost compound selector" definition serves as the basis of mainstream CSS selector engines, and these two features seek to challenge it altogether.

    这也是为什么 :has() 暂时被排除在 快速配置文件,因此可能无法在 CSS 中使用,因为它需要在页面渲染期间进行实时选择器匹配,这种情况无疑对性能至关重要.它仍然可以通过 DOM 方法访问 querySelector(), querySelectorAll()matches() (以及任何碰巧使用它们的选择器库),但是.

    This is also why :has() is tentatively excluded from the 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() (and any selector libraries that happen to make use of them), however.

    也就是说,CSSWG 有计划测试 :has() 的有限变体(例如使用单个子组合器或兄弟组合器),看看它们是否可以很好地实现以包含在 CSS 中,这将满足 vast 大多数用例,包括上面的第一个例子.

    That said, the CSSWG has plans to test limited variations of :has() (e.g. with a single child combinator or sibling combinator) to see if they can be implemented well enough to be included in CSS, which will fulfill the vast majority of use cases, including the first example above.

    不幸的是,今天的 CSS 选择器语法仍然非常有限;然而,该标准的新提案将带来强大的新可能性,其中一些新增功能基于 jQuery 等选择器库已经提供的功能.希望实现将支持这些新功能以用于 CSS.

    Unfortunately, CSS selector syntax remains extremely limited today; however, new proposals to the standard are set to bring powerful new possibilities, and a handful of these additions are based on features that selector libraries such as jQuery already offer. Here's hoping that implementations will support these new features for use in CSS.

    这篇关于如何使用 CSS 根据页面中另一个元素的状态选择一个元素?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆