如何根据CSS页面中另一个元素的状态select一个元素?

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

我可以定位具有改变状态的元素,但是我似乎无法find一种方法来根据元素的状态来定位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> 

或者只是使用适当的服务器端样式呈现元素。

有没有一个CSSselect器,让我指定哪些元素应根据目标元素的状态来select?

就像是:

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

这也可以让我也瞄准与CSS只具有相同的父母的元素

对规范问题的一般答复

如何根据CSS页面中另一个元素的状态select一个元素?

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

  1. 是否可以用简单的select器来表示这些元素的状态,
  2. 在这两个元素之间是否可以使用组合来expression一个结构关系,以形成一个复杂的select器
  3. 是否要将目标元素作为生成的复杂select器的主题。

虽然目前的select器标准有一些有趣的function,但有时候可能会有很强大的function,但它的devise方式使其在2号区域受到极大限制(其中#3是直接后果)。 其他答案列举了其中一些有限的可能性,例如通过儿童和兄弟组合的最基本的使用, 巧妙地使用dynamic伪类 (实际上与条件#1有关)或两者的组合 。

另一方面,问题中给出的问题无法使用select器中可用的内容来解决。 其中大部分归结为缺less父母select器和/或先前的兄弟select器,这两者似乎都是微不足道的function,但有一定的含义使得它们很难定义或实施。 综上所述:

  1. 是的,这些元素的状态可以用简单的select器来表示: div[data-status~=finished] .blink [data-status~=finished]为前者,后者为.blink.spin

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

  3. 假设前两个问题的答案也是“是”,则.blink.spin每一个都可以作为自己的复合select器的主题。 (但更多的在下一节中。)

如果你已经被引导到这个问题,那么你正试图解决的问题就像上面给出的那样,由于这些限制,select器无法解决。

即将到来的标准提供了一些新的function,将大大丰富select器的语法,并有可能将其打开(和CSS)到许多新的可能性,包括示例问题的可能解决scheme。 所有这些内容将在下面的章节中进行介绍,但是首先我将解释每个条件的含义以及它与给定示例的关系。

元素状态和元素之间的结构关系

select器的定义特征是表示文档树中一个或多个元素的特定结构。 这不仅仅是我编写的 – 你可以在Selectors标准的信息概览中find这个描述:

select器代表一个结构。 这个结构可以被用作一个条件(例如在一个CSS规则中),它决定了一个select器在文档树中匹配哪些元素,或者作为对应于该结构的HTML或XML片段的平面描述。

select器的范围可以从简单的元素名称到丰富的上下文表示。

每个元素由一个或多个简单的select器序列表示。 这个序列被称为复合select器(我在这里使用了select器4中的术语,因为它比select器3中使用的更清晰 – 请参阅此答案以获得非穷举的术语列表)。

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

在给定的例子中,具有data-status属性的div元素,其空格分隔的值包含finished可以用一个typesselect器和一个属性select器来表示:

 div[data-status~=finished] 

如果您希望select器只在指针位于此元素上时才应用,则只需input:hover伪类:

 div[data-status~=finished]:hover 

复合select器通过组合器连接形成复杂的select器。 这些组合符,你可能熟悉的>+~符号表示每个复合select符代表的元素之间的关系。 有了这两个工具,就可以创build一些非常有趣的结果,如其他答案所示。 我在这个答案中更深入地解释了这些基础知识。

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

  • 第一个元素是div[data-status~=finished]的父元素。 这是使用子组合器>来表示的:

     section > div[data-status~=finished] 
  • 第二section紧接着第一section作为它的兄弟姐妹。 这是用相邻的兄弟组合符号+

     section + section 
  • 另外,第二section.blink.spin的父.spin 。 这可以用两个select器来表示,每个孩子一个:

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

    为什么需要两个select器? 在这种情况下,主要是因为目前没有将两个复合select器分组到一个的语法,所以您将不得不分别表示每个子元素。 即将推出的Selectors 4标准引入了一个:matches()伪类,它将提供以下的子分组function:

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

现在,由于复杂select器中的每个复合select器代表一个元素,因此section + section代表两个同胞元素, section > div代表父节点和子节点, section + section > div代表下一个兄弟节点的子节点,你会认为一个父组合子和一个前兄弟组合子是相当多余的。 那么为什么我们通常会得到这些问题:

  • 有一个CSS父母select器?
  • 有一个“以前的兄弟”CSSselect器?

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

select者的主题

select器的主题总是由最右边的复合select器表示。 例如,select器section + section > div代表三个元素,其中div是主题。 你可能会说div是被选中的 ,或者是针对性的,但是如果你曾经想知道是否有合适的术语,那么它就是select者的主题。

在CSS规则中,样式应用于由select器的主体表示的元素。 任何子框和伪元素框在适当的地方inheritance这个元素的样式。 (例外是,如果select器的主题包含一个伪元素,在这种情况下,样式直接应用于伪元素。)

从上一节的select器中,我们得到以下几点:

  • section > div[data-status~=finished]div[data-status~=finished]
  • section + section的主题是第二个 sectionselect器。
  • section + section > .blink, section + section > .spin.spin分别是.blink.spin
  • 使用:matches()section + section > :matches(.blink, .spin):matches(.blink, .spin)

因此可能看起来我们确实需要一个父select器或一个先前的兄弟select器。 但请记住,select器已经可以表示复杂的结构。 与其简单地添加与现有工具相反的新组合器,寻求更灵活的解决scheme是有意义的,这正是CSSWG所做的。

这从原来的问题带给我们以下几点:

有没有一个CSSselect器,让我指定哪些元素应根据目标元素状态select?

答案是否定的,将不会。 然而,在select器4(从FPWD到2013年5月的最新工作草案 )的早期草案中,有人提出了一个新特性,可以让你select除最右边之外的任何复合select器,并指定那作为select的主题。

潜在的解决scheme

然而,这个主题指标最近被删除了:has()伪类(这反过来被jQuery所采用 )。 我在这里推测一个可能的原因:

原因:has()更通用是因为,在主题select器中,如果一个复杂select器可能有多个主题select器(因为一个复杂select器只能有一个主题)和/或如果function伪类如:matches()接受了主题select器。 但是因为伪类是一个简单的select器,所以你知道:has()在接受伪类的任何地方都可以接受:has()

所以,虽然你不能改变select器的主题,但由于它的伪类本质, :has()将完全写出需要这样做的需要。 而最好的部分是它做到了这一点 – 然后是一些 – 所有这些都没有从根本上改变select器的语法。

实际上, 可以使用select器4 来解决示例问题:has()

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

注意使用了一个子组合器:这个作用域的相对select器参数只是第一section 。 是的,这是世界各地Web开发人员多年来一直想要的难以捉摸的“父母select器”。

因为:has()来自jQuery,所以今天可以使用它,虽然:matches()还不存在,所以你必须在同时调用.filter()来replace它。

 $('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> 

你在CSS的当前状态下可以实现的function非常有限。

简而言之,如果CSS元素具有相同的父类和父类的子元素,则可以使CSS元素对元素的状态变化做出反应。


CSS中元素的状态由伪类处理,它涵盖了浏览器基于用户input处理的大部分典型交互。

虽然这使您能够处理DOM树中元素及其子元素的当前状态的视觉外观,但您仍然无法使其他非子元素对您的当前状态作出反应(通过视觉更改样式)元素,因为CSS不提供特定types的select器以灵活的方式做到这一点。

但是,您可以将伪类与其他types的CSSselect器结合起来,并在某些情况下使用这个工作(我将使用hover状态,因为它是最明显的):

伪类+邻居兄弟select器

如果element1element2在文档树中共享同一父element2并且element1紧接在element2之前,则相邻的兄弟select器匹配。 ( 相邻兄弟select器的W3C规范 )

 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> 

由于@easwee已经发布了一个很好的答案,我不会重复他讨论过的任何伪类select器,


现在我们有一个新的伪类,在css3中是:target

CSS中的:target伪select符与URL中的散列值和元素的id相同时匹配。

(target的具体用法是在视口顶部设置目标和可见的样式元素)

所以这实际上可以(错误)使用,基于用户交互(具体点击),以改变其他元素样式,当与另一个伪类或兄弟select器使用。

例如:父母的兄弟姐妹的目标孩子。

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