题 是否有“以前的兄弟”CSS选择器?


+ 是为了下一个兄弟姐妹。以前的兄弟姐妹是否有同等效力?


1035
2017-11-30 04:06


起源




答案:


不,没有“以前的兄弟”选择器。

在相关的说明, ~ 是一般继承兄弟(意思是元素在此之后,但不一定紧接在之后)并且是CSS3选择器。 + 是为了下一个兄弟,是CSS2.1。

看到 相邻的兄弟组合子 从 选择者等级3 和 5.7相邻的兄弟选择器 从 层叠样式表2级修订版1(CSS 2.1)规范


667
2017-11-30 04:08



从CSS3标准: 由两个序列表示的元素 分享同一个父母 在文档树和第一个序列表示的元素中 先于 (不一定是立即)由第二个元素表示的元素。 - Lie Ryan
@Lie Ryan:是的,但是他的回答是关键是你没有 选择 前面的元素。 - BoltClock♦
这是我做的一个例子,看看它能做什么,不能做什么。 jsfiddle.net/NuuHy/1 - Abacus
对此有用的jquery函数是prev()。例如$(“#the_element”)。prev()。css(“background-color”,“red”) - Satbir Kira
根据您的标记,这可能会有所帮助: stackoverflow.com/questions/42680881/... - samnau


我找到了一种方式来塑造所有以前的兄弟姐妹(相反的 ~)可能会根据您的需要而有效。

假设你有一个链接列表,当悬停在一个链接上时,所有以前的链接都应该变为红色。你可以这样做:

/* default link color is blue */
.parent a {
  color: blue;
}

/* prev siblings should be red */
.parent:hover a {
  color: red;
}
.parent a:hover,
.parent a:hover ~ a {
  color: blue;
}
<div class="parent">
  <a href="#">link</a>
  <a href="#">link</a>
  <a href="#">link</a>
  <a href="#">link</a>
  <a href="#">link</a>
</div>


160
2018-01-16 22:45



您可以添加其工作原理的说明。 (似乎您将样式应用于所有项目以及以下项目,但可以明确说明) - A.L
这是我上面提到的小提琴: jsfiddle.net/y9zeLr1n - Steven Vachon
是的,但大部分时间都需要一个以前的,而不是以前的所有! - azerafati
对我来说,如果我将它们悬停在它们之间的空间上,这些链接都会变成红色。 - Lynn
@Lynn答案只包括在悬停时使前一个链接变红的代码。其他样式取决于您的用例。对于星级评分组件(我猜这是常见的情况),你需要摆脱那个空间,并使红色的悬停链接。 - mantish


选择器4级介绍 :has() (以前是主题指标 !)这将允许您选择以前的兄弟:

previous:has(+ next) {}

...但在撰写本文时,对于浏览器支持而言,这是一个超越前沿的距离。


118
2018-03-19 15:19



真正的答案是:css选择器旨在为浏览器轻松(快速)实现。可以遍历该文档 一旦,随时匹配元素,无需向后调整匹配。 - chowey
“浏览器支持的流血边缘” 可能是夸大其词。截至撰写本文时,即使是最新版本的Chrome也无法使用 :has() 伪类。 - Reed Martin
该 :has() 选择器在样式表中特别不可用,即您可以在Javascript中使用它 - James Tudsbury
@chowey - 您的计算机可以处理疯狂的视频游戏,在高FPS下进行无数的数学计算,但浏览器几乎无法处理CSS中先前元素的样式。多么讽刺。 - vsync
@ReedMartin - 这就是我说的原因 距离出血边缘有一段距离 - Quentin


考虑一下 order 柔性和网格布局的属性。

我将在下面的示例中关注flexbox,但相同的概念适用于Grid。


使用flexbox,可以模拟先前的兄弟选择器。

特别是flex order 属性可以在屏幕上移动元素。

这是一个例子:

当元素B悬停时,您希望元素A变为红色。

<ul>
    <li>A</li>
    <li>B</li>
</ul>

脚步

  1. 制作 ul 一个弹性容器。

    ul { display: flex; }
    

  1. 在标记中反转兄弟姐妹的顺序。

    <ul>
       <li>B</li>
       <li>A</li>
    </ul>
    

  1. 使用兄弟选择器来定位元素A(~ 要么 + 会做) 。

    li:hover + li { background-color: red; }
    

  1. 使用flex order 在视觉显示上恢复兄弟姐妹的顺序的属性。

    li:last-child { order: -1; }
    

......瞧!先前的兄弟选择器诞生(或至少模拟)。

这是完整的代码:

ul {
    display: flex;
}

li:hover + li {
    background-color: red;
}

li:last-child {
    order: -1;
}

/* non-essential decorative styles */
li {
    height: 200px;
    width: 200px;
    background-color: aqua;
    margin: 5px;
    list-style-type: none;
    cursor: pointer;
}
<ul>
    <li>B</li>
    <li>A</li>
</ul>

来自flexbox规范:

5.4。显示顺序: order 属性

默认情况下,Flex项目的显示和排列顺序与它们在源文档中显示的顺序相同。该    order 属性可用于更改此顺序。

order 属性控制弹性项目在弹性容器中的显示顺序,方法是将它们分配给顺序组。它只需一个 <integer> value,指定flex项的哪个序数组   属于。

最初的 order 所有弹性项的值为0。

另见 order 在CSS网格布局规范中


使用flex创建的“以前的兄弟选择器”的示例 order 属性。

.container { display: flex; }

.box5 { order: 1; }    
.box5:hover + .box4 { background-color: orangered; font-size: 1.5em; }

.box6 { order: -4; }
.box7 { order: -3; }
.box8 { order: -2; }
.box9 { order: -1; }
.box9:hover ~ :not(.box12):nth-child(-1n+5) { background-color: orangered;
                                              font-size: 1.5em; }
.box12 { order: 2; }
.box12:hover ~ :nth-last-child(-1n+2) { background-color: orangered;
                                        font-size: 1.5em; }
.box21 { order: 1; }
.box21:hover ~ .box { background-color: orangered; font-size: 1.5em; }

/* non-essential decorative styles */
.container {
    padding: 5px;
    background-color: #888;
}
.box {
    height: 50px;
    width: 75px;
    margin: 5px;
    background-color: lightgreen;
    display: flex;
    justify-content: center;
    align-items: center;
    text-align: center;
    cursor: pointer;
}
<p>
Using the flex <code>order</code> property to construct a previous sibling selector
</p>

<div class="container">
    <div class="box box1"><span>1</span></div>
    <div class="box box2"><span>2</span></div>
    <div class="box box3"><span>3</span></div>
    <div class="box box5"><span>HOVER ME</span></div>
    <div class="box box4"><span>4</span></div>
</div>

<br>

<div class="container">
    <div class="box box9"><span>HOVER ME</span></div>
    <div class="box box12"><span>HOVER ME</span></div>
    <div class="box box6"><span>6</span></div>
    <div class="box box7"><span>7</span></div>
    <div class="box box8"><span>8</span></div>
    <div class="box box10"><span>10</span></div>
    <div class="box box11"><span>11</span></div>
</div>

<br>

<div class="container">
    <div class="box box21"><span>HOVER ME</span></div>
    <div class="box box13"><span>13</span></div>
    <div class="box box14"><span>14</span></div>
    <div class="box box15"><span>15</span></div>
    <div class="box box16"><span>16</span></div>
    <div class="box box17"><span>17</span></div>
    <div class="box box18"><span>18</span></div>
    <div class="box box19"><span>19</span></div>
    <div class="box box20"><span>20</span></div>
</div>

的jsfiddle


附注 - 关于CSS的两种过时信念

Flexbox打破了人们对CSS的长期信念。

一个这样的信念是 CSS中无法使用上一个兄弟选择器

说这种信念是普遍的,这是轻描淡写的。以下是Stack Overflow相关问题的示例:

如上所述,这种信念并不完全正确。可以使用flex在CSS中模拟先前的兄弟选择器 order 属性。

z-index 神话

另一个长期存在的信念是 z-index 仅适用于定位元素。

事实上,最新版本的规格 - W3C编辑的草稿  - 仍然断言这是真的:

9.9.1指定堆栈级别: z-index   属性

z-index

  • 价值:汽车| |继承
  • 初始:自动
  • 适用于:定位元素
  • 继承:没有
  • 百分比:N / A.
  • 媒体:视觉
  • 计算值:如指定的那样

(重点补充)

但实际上,这些信息已经过时且不准确。

元素是 弹性物品 要么 网格项目 甚至可以创建堆叠上下文 position 是 static

4.3。 Flex项目Z-Ordering

Flex项目绘制与内联块完全相同,除了使用订单修改的文档顺序代替原始   文件订单,和 z-index 除了 auto 即使创建堆叠上下文 position 是 static

5.4。 Z轴订购: z-index 属性

网格项的绘制顺序与内联块完全相同,但订单修改的文档顺序除外   用来代替原始文件订单,和 z-index 除了 auto 即使创建堆叠上下文    position 是 static

这是一个演示 z-index 处理未定位的flex项目: https://jsfiddle.net/m0wddwxs/


99
2018-03-20 18:49



该 order 财产不是解决方案,因为它只是为了改变 视觉 订单,所以它 不 恢复原来的 语义 命令您不得不在HTML中更改此解决方法才能工作。 - Marat Tanalin
@Marat Tanalin:对于90%的用例,假设浏览器支持不是问题,这可以正常工作。其余10%的用例是1)改变视觉顺序不是解决方案的情况,或2)根本不涉及CSS的情况。值得庆幸的是,对于#2,selectors-4提供:has(),并且只需要选择器库的开发人员来实现它。 - BoltClock♦
请记住,您引用的CSS2.2 ED实际上仍然是CSS2。 CSS2中不存在flexbox和网格布局,因此就CSS2而言,该信息肯定是正确的。至少,可以更新文本以提及z-index可以应用于未来CSS级别中的其他类型的元素,就像它说其他属性可以建立堆叠上下文一样,例如不透明度。 - BoltClock♦
万一有人在理解什么时候有困难 z-index 会工作,即使“omg,没有 position 指定!“,规范提到了概念 堆叠上下文,很好地解释了 这篇关于MDN的文章 - Rogier Spieker
@Michael_B,欢迎你!我已经处理了很多不知道这件事的前锋。还有一件事我想提一下, 仿前兄弟选择器 也很好用 float: right (或任何其他方式来扭转其排序,其中 flex/order 几乎没有(最少?)副作用)。掀起两个小提琴: 展示了 float: right 途径,和 示范 direction: rtl - Rogier Spieker


我有同样的问题,但后来我有一个“呃”的时刻。而不是写作

x ~ y

y ~ x

显然这匹配“x”而不是“y”,但它回答“有匹配吗?”问题,简单的DOM遍历可以比在javascript中循环更有效地使你到达正确的元素。

我意识到最初的问题是一个CSS问题所以这个答案可能完全无关紧要,但其他Javascript用户可能会像我一样通过搜索偶然发现问题。


65
2017-11-30 16:40



我相信这很容易找到y。问题是如果y只能相对于x找到,并且在反转它时,你找不到y,因为你必须首先找到x。这当然是关于y在兄弟之前而不是在下一个之前的问题,但也可能适用于y是以下兄弟。 - David
苛刻,你有点苛刻。 (抱歉,无法抗拒。)重点是,有时候你只需要知道“你们存在吗?”。其他时候你可以使用“:before”在两个元素之间放置一些东西。最后,如果你必须使用find(“y~x”)进入jQuery,则prev()比许多替代方案更容易。 - Bryan Larsen
先前兄弟选择器的想法是它将选择前一个元素。不幸的是,如此处所述,逆转它并不提供此功能。 - Zenexer
感谢@Zenexer澄清这个答案没有提供原始问题的实际解决方案,我开始觉得自己愚蠢地思考如何 y ~ x 可以解决我的问题 - Jaime Hablutzel
我理解这个答案背后的想法,但是答案中给出的推理并没有多大意义。选择器 y ~ x 不回答“有匹配吗?”问题,因为这里给出的两个选择器意味着完全不同的东西。不可能 y ~ x给出子树可以产生匹配 <root><x/><y/></root> 例如。如果问题是“存在吗?”那么选择器很简单 y。如果问题是“在给定任意位置的兄弟x的情况下是否存在?”那么你需要 都 选择。 (虽然也许我只是在这一点上挑剔...) - BoltClock♦


技巧。基本上反转HTML中所需元素的HTML顺序并使用
~  下一个兄弟姐妹 运营商:

float-right  + 逆转HTML元素的顺序

div{ /* Do with the parent whatever you know just to make the
  inner float-right elements appear where desired */
  display:inline-block;
}
span{
  float:right;  /* float-right the elements! */
}
span:hover ~ span{ /* On hover target it's "previous";) elements */
  background:red;
} 
<div>
  <!-- Reverse the order of inner elements -->
  <span>5</span>
  <span>4</span>
  <span>3</span>
  <span>2</span>
  <span>1</span>
</div>


家长 direction: rtl; +逆内元素的顺序

.inverse{
  direction: rtl;
  display: inline-block; /* inline-block to keep parent at the left of window */
}
span:hover ~ span{ /* On hover target it's "previous";) elements */
  background:gold;
}
Hover one span and see the previous elements being targeted!<br>

<div class="inverse">
  <!-- Reverse the order of inner elements -->
  <span>5</span>
  <span>4</span>
  <span>3</span>
  <span>2</span>
  <span>1</span>
</div>


20
2017-08-19 01:52





+ 是为了下一个兄弟姐妹。有没有与以前相同的   兄弟?

你可以使用这两个 斧头 选择: ! 和 ?

2 随后的兄弟选择者


12
2018-04-25 09:59



当我尝试在rails项目中的sass上实现它时,这给了我一个语法错误。 - alex
斧头 是一个CSS后处理器。它不使用与CSS预处理器相同的语法,如Sass,Less或Stylus。 - Rounin


另一个flexbox解决方案

您可以使用HTML中的元素顺序。然后除了使用 order 如在 Michael_B的回答 您可以使用 flex-direction: row-reverse; 要么 flex-direction: column-reverse; 取决于您的布局。

工作样本:

.flex {
  display: flex;
  flex-direction: row-reverse;
   /* Align content at the "reversed" end i.e. beginning */
  justify-content: flex-end;
}

/* On hover target its "previous" elements */
.flex-item:hover ~ .flex-item {
  background-color: lime;
}

/* styles just for demo */
.flex-item {
  background-color: orange;
  color: white;
  padding: 20px;
  font-size: 3rem;
  border-radius: 50%;
}
<div class="flex">
  <div class="flex-item">5</div>
  <div class="flex-item">4</div>
  <div class="flex-item">3</div>
  <div class="flex-item">2</div>
  <div class="flex-item">1</div>
</div>


11
2018-01-14 17:33





目前没有正式的方法可以做到这一点,但你可以用一个小技巧来实现这一目标!请记住它是实验性的,它有一些限制...... (检查 这个链接 如果你担心导航兼容性)

你可以做的是使用CSS3选择器:伪classe调用 nth-child()

#list>* {
  display: inline-block;
  padding: 20px 28px;
  margin-right: 5px;
  border: 1px solid #bbb;
  background: #ddd;
  color: #444;
  margin: 0.4em 0;
}

#list :nth-child(-n+4) {
  color: #600b90;
  border: 1px dashed red;
  background: orange;
}
<p>The oranges elements are the previous sibling li selected using li:nth-child(-n+4)</p>

<div id="list">
  <span>1</span><!-- this will be selected -->
  <p>2</p><!-- this will be selected -->
  <p>3</p><!-- this will be selected -->
  <div>4</div><!-- this will be selected -->
  <div>5</div>
  <p>6</p>
  <p>7</p>
  <p>8</p>
  <p>9</p>
</div>

限制

  • 您无法根据下一个元素的类选择以前的元素
  • 伪类也是如此

11
2017-09-03 16:16



为什么他们必须是同一个节点?为什么不用 :nth-child(-n+4)? - Ian
@Ian因为 :nth-child(-n+4) 是一个伪类,需要应用于选择器才能正常工作。如果你没有说服力,试着用我的小提琴的叉子进行试验,你就会发现它不会起作用 - 0x1gene
实际上,你可以使用。来节点类型独立 * 选择器,但这是令人讨厌的糟糕做法。 - Josh Burgess
这个答案对我有用,不知道为什么它没有被投票更高或被接受。 - Jake Cattrall
实际上,它适用于不同的节点: jsfiddle.net/aLhv9r1w/316。请更新你的答案:) - Jamie Barker