1795

The plus sign selector (+) is for selecting the next adjacent sibling.

Is there an equivalent for the previous sibling?

TylerH
  • 20,799
  • 66
  • 75
  • 101
Jourkey
  • 33,710
  • 23
  • 62
  • 78
  • you don't need it because you can do everything with the combination of the general selector plus the next sibling selector. – Gabriel Linassi Jan 14 '21 at 18:23
  • 7
    I'm not sure you can in all cases, and even if so - it's very hard to read and reason about and therefore should be added as a convenience imo – Ben Taliadoros May 13 '21 at 10:36
  • which combinator can use for parent selector ?, @GabrielLinassi – vishal Feb 23 '22 at 11:52
  • This can be achieved using: display: flex; flex-direction: row-reverse; – Scott Mar 11 '22 at 21:31
  • 1
    This is definitely an oversight from the people who designed CSS selectors. When you have a next selector it makes sense to have a previous selector also even if the same can be achieved in some other way. I hope it is added in the future. I have been plagued by this issue on several occasions and have to use some other selector combination to achieve my goal which is not elegant. – Indra Sep 09 '22 at 15:59
  • using has: selector since its support is more available nowadays: https://tobiasahlin.com/blog/previous-sibling-css-has/ – tonnoz May 20 '23 at 11:08

33 Answers33

1018

No, there is no "previous sibling" selector.

On a related note, ~ is for general successor sibling (meaning the element comes after this one, but not necessarily immediately after) and is a CSS3 selector. + is for next sibling and is CSS2.1.

See Adjacent sibling combinator from Selectors Level 3 and 5.7 Adjacent sibling selectors from Cascading Style Sheets Level 2 Revision 1 (CSS 2.1) Specification.

Domenic
  • 110,262
  • 41
  • 219
  • 271
cletus
  • 616,129
  • 168
  • 910
  • 942
  • 20
    From the CSS3 standard: *The elements represented by the two sequences **share the same parent** in the document tree and the element represented by the first sequence **precedes** (not necessarily immediately) the element represented by the second one.* – Lie Ryan Feb 26 '11 at 16:34
  • 33
    @Lie Ryan: Yeah, but the point cletus is making in his answer is that you don't **select** the preceding element. – BoltClock Mar 29 '11 at 21:05
  • 57
    Here's an example I made to see what this can, and can't, do. http://jsfiddle.net/NuuHy/1/ – Abacus Jul 17 '13 at 18:26
  • 11
    The jquery function useful for this is prev(). For example $("#the_element").prev().css("background-color", "red") – Satbir Kira May 18 '15 at 21:11
  • There are different methods to select the previous, via simple vanilla js – The Myth Oct 28 '22 at 12:07
  • While it's true that there is no pure CSS previous sibling selector, for any practical use a workaround can be achieved with existing selectors combinations - as shown in the attached answer. Please consider editing your answer to include the link below, as it should be good enough for most use cases https://stackoverflow.com/a/12198561/10564382 – jonyB Jan 10 '23 at 10:50
348

I found a way to style all previous siblings (opposite of ~) that may work depending on what you need.

Let's say you have a list of links and when hovering on one, all the previous ones should turn red. You can do it like this:

/* 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>
mantish
  • 6,598
  • 2
  • 16
  • 9
  • 24
    You can add an explanation of how it works. (it seems that you apply an style to all the items and to the following items but it can de described explicitly) – A.L Apr 24 '15 at 17:04
  • 17
    yea, but a single previous is needed most of the time NOT ALL the previous ones! – azerafati May 01 '16 at 15:15
  • 73
    The links all turn red if I hover over the space between them, for me. – Lynn Aug 01 '16 at 08:19
  • All tags turn red when hovering over the parent–but at the same time not hovering over any of the child a tags–due to the `.parent:hover a` style. – Joe Van Leeuwen Nov 10 '21 at 17:35
  • @Lynn @JoeVanLeeuwen yes, this example only includes the minimum amount of rules to target previous siblings. To remove spacing you'd need to add more rules, probably changing the `display` of the contender – mantish Nov 12 '21 at 10:30
  • This is a very cunning solution! The basic idea is to invert previous to be next: a) define a `starting state` b) on hover let's turn `all siblings` into how `previous siblings` should look c) then revert the `current` and `next siblings` elements back to the `starting state`, leaving only `previous elements` looked changed. – atoth Apr 26 '22 at 11:41
  • But you are not working with siblings, we are working here all the time with the parent. I mean, if you are allowed to add extra tags or use parent you can use the id of the corresponding sibling or use :nth-child("position") to work – Mbotet Sep 28 '22 at 08:13
  • This technique seems to apply only when all your child elements are more-or-less the same entity, with shared styles. For instance, what if I have `
    ` and I want to say "if a link is followed by a `.foo` div, color it red; else color it blue"? There doesn't seem to be any way to do that without a real "previous" selector.
    – Sasgorilla Feb 27 '23 at 18:37
339

Selectors level 4 proposes :has() (previously the subject indicator !) which will, one day, allow you to select a previous sibling with:

previous:has(+ next) {}

or (for a general previous sibling rather than adjacent one):

previous:has(~ next) {}

At the time of writing :has{} is supported by most but not all major browsers. Support is improving.


Over the years this answer has attracted dozens of "It's still not supported" comments (now deleted). Please don't add any more. There's a link to an regularly updated browser support chart in the answer.

Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335
211

Consider the order property of flex and grid layouts.

I'll focus on flexbox in the examples below, but the same concepts apply to Grid.


With flexbox, a previous sibling selector can be simulated.

In particular, the flex order property can move elements around the screen.

Here's an example:

You want element A to turn red when element B is hovered.

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

STEPS

  1. Make the ul a flex container.

    ul { display: flex; }
    

  1. Reverse the order of siblings in the mark-up.

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

  1. Use a sibling selector to target Element A (~ or + will do) .

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

  1. Use the flex order property to restore the order of siblings on the visual display.

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

...and voilà! A previous sibling selector is born (or at least simulated).

Here's the full code:

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>

From the flexbox spec:

5.4. Display Order: the order property

Flex items are, by default, displayed and laid out in the same order as they appear in the source document. The order property can be used to change this ordering.

The order property controls the order in which flex items appear within the flex container, by assigning them to ordinal groups. It takes a single <integer> value, which specifies which ordinal group the flex item belongs to.

The initial order value for all flex items is 0.

Also see order in the CSS Grid Layout spec.


Examples of "previous sibling selectors" created with the flex order property.

.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


A Side Note – Two Outdated Beliefs about CSS

Flexbox is shattering long-held beliefs about CSS.

One such belief is that a previous sibling selector is not possible in CSS.

To say this belief is widespread would be an understatement. Here's a sampling of related questions on Stack Overflow alone:

As described above, this belief is not entirely true. A previous sibling selector can be simulated in CSS using the flex order property.

The z-index Myth

Another long-standing belief has been that z-index works only on positioned elements.

In fact, the most current version of the spec – the W3C Editor's Draft – still asserts this to be true:

9.9.1 Specifying the stack level: the z-index property

z-index

  • Value: auto | | inherit
  • Initial: auto
  • Applies to: positioned elements
  • Inherited: no
  • Percentages: N/A
  • Media: visual
  • Computed value: as specified

(emphasis added)

In reality, however, this information is obsolete and inaccurate.

Elements that are flex items or grid items can create stacking contexts even when position is static.

4.3. Flex Item Z-Ordering

Flex items paint exactly the same as inline blocks, except that order-modified document order is used in place of raw document order, and z-index values other than auto create a stacking context even if position is static.

5.4. Z-axis Ordering: the z-index property

The painting order of grid items is exactly the same as inline blocks, except that order-modified document order is used in place of raw document order, and z-index values other than auto create a stacking context even if position is static.

Here's a demonstration of z-index working on non-positioned flex items: https://jsfiddle.net/m0wddwxs/

Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
  • 33
    The `order` property is not a solution since it is solely intended to change _visual_ order, so it does _not_ restore the original _semantical_ order that you are forced to change in HTML for this workaround to work. – Marat Tanalin Mar 20 '16 at 21:47
  • 2
    @Marat Tanalin: For 90% of use cases, assuming browser support isn't an issue, this will work just fine. The remaining 10% of use cases are either 1) cases where changing the visual order isn't a solution, or 2) cases that don't involve CSS at all. Thankfully, for #2, selectors-4 provides :has(), and it's simply up to the developers of selector libraries to implement it. – BoltClock Mar 21 '16 at 04:52
  • 1
    Actually, you know what, I made those stats up. It's probably more like 50-50, or 10-90, or something. The point is that, as now stated, this is just one solution that works for some people. But saying that "contrary to popular belief, there *is* in fact a previous sibling selector" is misleading at best, because it involves a layout technique, not a selector technique, which falls flat in use cases that don't involve CSS layout. This is why I've lately been much more picky about distinguishing between "pure CSS" and "pure CSS *selectors*". – BoltClock Mar 21 '16 at 04:56
  • 5
    Keep in mind that the CSS2.2 ED you're citing is, in essence, still CSS2. And flexbox and grid layout don't exist in CSS2, so as far as CSS2 is concerned, that information certainly holds true. At the very least, the text could be updated to mention that z-index may apply to other types of elements in future levels of CSS, the same way that it says other properties may establish a stacking context, such as opacity. – BoltClock Mar 21 '16 at 05:05
  • 3
    @BoltClock My comment has nothing to do with browser support. The technique breaks semantics in favor of presentation. I believe a plain regular class added to previous-sibling element on server side is much more reasonable. – Marat Tanalin Mar 21 '16 at 09:34
  • @BoltClock, I appreciate your feedback. I see this entire thing from a practical perspective. And I wrote the answer for practical purposes. For developers who wish to target previous siblings on visual media, this technique may be useful. From the perspective of site users, previous siblings are being selected. So, for *practical* purposes, this can be deemed a previous sibling selector. – Michael Benjamin Mar 21 '16 at 10:37
  • 1
    From a technical perspective, I would agree this is not a PSS. But I generally try to provide answers that help solve real-world problems. I think this answer does that, using valid code and pure CSS. – Michael Benjamin Mar 21 '16 at 10:42
  • 3
    In case anyone is having trouble understanding when `z-index` will work, even when "omg, there's no `position` specified!", the specification mentions the concept of _stacking context_, which is explained nicely by [this article on MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context) – Rogier Spieker Apr 28 '16 at 17:45
  • @RogierSpieker, thanks for posting that MDN article. I read it a while back and it's very helpful. I also wrote this, which also tries to explain stacking contexts: http://stackoverflow.com/a/32515284/3597276 – Michael Benjamin Apr 28 '16 at 17:48
  • 3
    @Michael_B you're welcome! I've dealt with a lot of front-enders unaware of this. One other thing I'd like to mention, the _faux previous sibling selector_ also works nicely with `float: right` (or any other means to reverse the ordering, of which `flex/order` has little (least?) side effects). Whipped up two fiddles: [demonstrating the `float: right` approach](https://jsfiddle.net/foozle/t9819puk/), and [demonstrating `direction: rtl`](https://jsfiddle.net/foozle/ajyoLc1g/) – Rogier Spieker Apr 28 '16 at 17:57
  • @RogierSpieker, agreed. `float:right` is another method. I didn't mention it in my answer since it was already covered by at least two other answers to this question. – Michael Benjamin Apr 28 '16 at 18:05
  • @OzanKurt, a previous sibling selector is not possible in CSS. Therefore, all workarounds provided in these answers are obviously hacks or *"cheats"*. Not sure what you were expecting. – Michael Benjamin Mar 04 '17 at 03:48
  • 2
    It's a common misconception that selectors have anything to do with the cascade. Cascading, as defined by CSS, happens on a per-element basis. There is nothing in theory that would preclude the existence of a previous sibling selector or make it an oxymoron - especially now that [Selectors has transcended Cascading Style Sheets altogether](https://blog.novalistic.com/archives/2018/01/using-css-selectors-for-non-css#history), rendering the CSS argument moot. – BoltClock Feb 05 '18 at 05:58
  • Thanks for this clarification. I've removed that section from my answer and made other updates. @BoltClock – Michael Benjamin Mar 11 '18 at 22:38
  • 1
    Also, great [analysis of CSS selectors utilized in non-CSS](https://blog.novalistic.com/archives/2018/01/using-css-selectors-for-non-css/). I appreciate your separation of concerns argument and will keep it in mind. I also perused many of the links you referenced, including [your whitespace in selectors](https://blog.novalistic.com/archives/2018/01/whitespace-in-css-selectors/), which was a useful refresher. Thanks, again. – Michael Benjamin Mar 11 '18 at 22:39
  • @MichaelBenjamin what if the list is dynamic? I am setting the position of the child elements to be absolute. So order doesn't change the position. But it seems to break things? and styles not applied to all the children. – MonteCristo May 10 '20 at 16:48
  • 1
    Just want to mention this would severely damage a11y. You should NOT use this. – Danny van Holten Jul 02 '20 at 08:27
  • 1
    @DannyvanHolten It depends on what content is being re-ordered. For most things there's no real issue with accessibility based on re-ordered contents, especially if you really care about a11y, wherein you should also be using things like taborder and aria-labels to help. – TylerH Dec 15 '20 at 17:45
  • @DannyvanHolten, how? Please elaborate. It's clear that developers need tools to solve their styling challenges. What does the order of elements have to do with the meaning of the content inside them, or their relation to each-other? – rjminchuk Jan 04 '21 at 02:02
  • @DannyvanHolten I withdraw my question. The example above shows the reordering of a
      with css order. I agree that lists should not have their order altered. Changing the order of a list (regardless if it's
      or
      ) with flex order is a bad idea for accessibility sake, primarily because of the
    • 's relation to it's parent element (an unordered list). The expectation for lists is that they are presented and read by a screen reader in the order they appear in the
        . You should NOT reorder a list-item. Only reorder elements with no semantic or hierarchical relation to each other.
    – rjminchuk Jan 04 '21 at 02:43
  • 1
    @rjminchuk correct. Also, does not change the tab order. This leads to very weird behavior, and if there is anything focusable inside re-ordered elements, focus will be most likely jumping around the page. – Danny van Holten Jan 14 '21 at 08:57
78

I had the same question, but then I had a "duh" moment. Instead of writing

x ~ y

write

y ~ x

Obviously this matches "x" instead of "y", but it answers the "is there a match?" question, and simple DOM traversal may get you to the right element more efficiently than looping in javascript.

I realize that the original question was a CSS question so this answer is probably completely irrelevant, but other Javascript users may stumble on the question via search like I did.

Bryan Larsen
  • 9,468
  • 8
  • 56
  • 46
  • 22
    I believe that works when y can be found easily. Problem is if y can only be found relative to x, and in reversing it, you can't find y because you have to find x first. This is of course in reference to the question of y being preceding sibling rather than next, but may also apply for y being a following sibling. – David Feb 12 '13 at 19:14
  • 19
    You're being kind of harsh, Harsh. (sorry, couldn't resist.) The point is that sometimes you just need to know "does y exist?". Other times you can use ":before" to put something between the two elements. Finally, if you do have to drop into jQuery, using find("y ~ x").prev() is easier than many alternatives. – Bryan Larsen Mar 13 '13 at 09:04
  • 185
    The idea of a previous sibling selector is that it will select the previous element. Unfortunately, reversing it, as described here, doesn't provide this functionality. – Zenexer Jul 31 '13 at 00:56
  • 1
    @BryanLarsen Applying logic without testing properly. That's not expected even though your answer seems smart enough. – Rajesh Paul Nov 03 '13 at 05:21
  • 17
    Thanks @Zenexer for the clarification that this answer doesn't provide an actual solution to the original question, I was starting to feel myself stupid thinking about how `y ~ x` could solve my problem – Jaime Hablutzel Apr 23 '14 at 21:20
  • I don't see how this works, it's this the same `y > x`? – limitlessloop Nov 07 '14 at 22:31
  • 1
    You're right, @sevenupcan, it doesn't work. The point of this answer is to get people to ask themselves if they *really* need x ~ y, can they make y ~ x work for them? Some people can, some people can't. It often times it makes sense to re-examine your question while looking for an answer. – Bryan Larsen Nov 10 '14 at 13:08
  • but I cannot using this when I am using the same tags but it is only possible when I have to use id , class or different tags – Muhammad Jun 06 '15 at 09:40
  • 6
    I understand the idea behind this answer, however the reasoning given in the answer doesn't quite make sense. The selector `y ~ x` doesn't answer the "is there a match?" question, because the two selectors given here mean completely different things. There is no way `y ~ x` could ever produce a match given the subtree `` for example. If the question is "does y exist?" then the selector is simply `y`. If the question is "does y exist given a sibling x in any arbitrary position?" then you'd need *both* selectors. (Though maybe I'm just nitpicking at this point...) – BoltClock Oct 27 '15 at 09:23
  • 1
    This is wrong. This selects x's that come after y's. But what you want to do is select x's that come before y's. – N73k May 18 '19 at 17:45
47

There's not "previous selector", but you can use the combination of :not and ~ ("after selector"). No reverse order, no javascript.

.parent a{
  color: blue
}

.parent a.active{
  color: red
}

.parent a:not(.parent a.active ~ a){
  color: red
}
<div class="parent">
  <a href="">link</a>
  <a href="">link</a>
  <a href="" class="active">link</a>
  <a href="">link</a>
  <a href="">link</a>
</div>

I think my approach is more straight-forward than "style all divs, than remove styling for after divs", or using javascript, or using reverse order.

Victor Gorban
  • 1,159
  • 16
  • 30
  • 7
    Off-note to readers: please note that this is not a previous sibling selector but rather a "general previous sibling" selector in that it will match any matching element, not just the previous one (does not take away from the solution, though, which is quite inventive). – Oleg Valter is with Ukraine Aug 06 '21 at 02:30
  • 1
    I used `.parent a:not(.parent a.active ~ a, a.active, .parent :first-child) { color: red }` to color only the second child. – CubicInfinity Aug 26 '21 at 18:29
  • This answer is like a complicated way of doing the 2015 answer by mantish – Huangism Aug 18 '22 at 16:00
  • Works for css tabs where the div to be displayed comes before the checked input!!! I didn't believe that someone could find such an inventive solution for the reverse order of tags: div-input as the normal order, input-div is easy to be coded!!! but still the answer about previous sibling selector remains no. – centurian Apr 08 '23 at 14:11
35

Three tricks:
basically, reversing the HTML order of your elements in HTML,
and using the ~ Next siblings operator:

1. Using CSS Flex and row-reverse

.reverse {
  display: inline-flex;
  flex-direction: row-reverse;
}
.reverse span:hover ~ span { /* On SPAN hover target its "previous" elements */
  background:gold;
}
Hover a SPAN and see the previous elements being styled!<br>

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

2. Using Flex with direction: RTL

.reverse {
  display: inline-flex;
  direction: rtl;
}
.reverse span:hover ~ span { /* On SPAN hover target its "previous" elements */
  background: red;
}
Hover a SPAN and see the previous elements being styled!<br>

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

3. Using float right

.reverse { 
  display: inline-block;
}
.reverse span{
  float: right; 
}
.reverse span:hover ~ span { /* On SPAN hover target its "previous" elements */
  background: red;
}
Hover a SPAN and see the previous elements being styled!<br>

<div class="reverse">
  <!-- Reverse the order of inner elements -->
  <span>5</span>
  <span>4</span>
  <span>3</span>
  <span>2</span>
  <span>1</span>
</div>
Roko C. Buljan
  • 196,159
  • 39
  • 305
  • 313
34

+ is for the next sibling. Is there an equivalent for the previous sibling?

You can use the two axe selectors: ! and ?

There are 2 subsequent sibling selectors in conventional CSS:

  • + is the immediate subsequent sibling selector
  • ~ is the any subsequent sibling selector

In conventional CSS, there is no previous sibling selector.

However, in the axe CSS post-processor library, there are 2 previous sibling selectors:

  • ? is the immediate previous sibling selector (opposite of +)
  • ! is the any previous sibling selector (opposite of ~)

Working Example:

In the example below:

  • .any-subsequent:hover ~ div selects any subsequent div
  • .immediate-subsequent:hover + div selects the immediate subsequent div
  • .any-previous:hover ! div selects any previous div
  • .immediate-previous:hover ? div selects the immediate previous div

div {
  display: inline-block;
  width: 60px;
  height: 100px;
  color: rgb(255, 255, 255);
  background-color: rgb(255, 0, 0);
  text-align: center;
  vertical-align: top;
  cursor: pointer;
  opacity: 0;
  transition: opacity 0.6s ease-out;
}

code {
  display: block;
  margin: 4px;
  font-size: 24px;
  line-height: 24px;
  background-color: rgba(0, 0, 0, 0.5);
}

div:nth-of-type(-n+4) {
  background-color: rgb(0, 0, 255);
}

div:nth-of-type(n+3):nth-of-type(-n+6) {
  opacity: 1;
}

.any-subsequent:hover ~ div,
.immediate-subsequent:hover + div,
.any-previous:hover ! div,
.immediate-previous:hover ? div {
  opacity: 1;
}
<h2>Hover over any of the blocks below</h2>

<div></div>
<div></div>

<div class="immediate-previous">Hover for <code>?</code> selector</div>
<div class="any-previous">Hover for <code>!</code> selector</div>
<div class="any-subsequent">Hover for <code>~</code> selector</div>
<div class="immediate-subsequent">Hover for <code>+</code> selector</div>

<div></div>
<div></div>

<script src="https://rouninmedia.github.io/axe/axe.js"></script>
TylerH
  • 20,799
  • 66
  • 75
  • 101
Rounin
  • 27,134
  • 9
  • 83
  • 108
  • 5
    This give me a syntax error when I try to implement it on sass inside a rails project. – alex Sep 05 '17 at 22:57
  • 36
    **axe** is a CSS post-processor. It does not use the same syntax as CSS pre-processors such as Sass, Less or Stylus. – Rounin Sep 06 '17 at 15:11
  • 2
    @Rounin would you mind adding some documentation links ? I cannot find *axe* post-processor. – Dionys May 27 '20 at 00:35
  • 1
    @Dionys - Thanks for your interest. _axe_ is a project I started in late 2016, when I didn't know ES2015 and even objects in JS were very new to me. The GitHub repository is here: https://github.com/RouninMedia/axe . I very much mean to return to this at some point (I've also developed something called _axe-blades_ which are the CSS equivalent of javascript events), but I need to complete my work on another project (codenamed **ashiva**) first. – Rounin May 27 '20 at 01:02
21

Another flexbox solution

You can use inverse the order of elements in HTML. Then besides using order as in Michael_B's answer you can use flex-direction: row-reverse; or flex-direction: column-reverse; depending on your layout.

Working sample:

.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>
Vadim Ovchinnikov
  • 13,327
  • 5
  • 62
  • 90
19

There is no official way to do that at the moment but you can use a little trick to achieve this ! Remember that it is experimental and it has some limitation ... (check this link if you worries about navigator compatibility )

What you can do is use a CSS3 selector : the pseudo classe called 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>

Limitations

  • You can't select previous elements based on the classes of the next elements
  • This is the same for pseudo classes
allicarn
  • 2,859
  • 2
  • 28
  • 47
0x1gene
  • 3,349
  • 4
  • 29
  • 48
  • Why do they have to be the same node? Why not just use `:nth-child(-n+4)`? – Ian Oct 27 '14 at 20:13
  • 1
    @Ian because the ```:nth-child(-n+4)``` is a pseudo class that needs to be apply to a selector in order to work properly. If you are not convince, try to experiment it using a fork of my fiddle and you'll see that it doesn't wok – 0x1gene Oct 28 '14 at 00:11
  • 1
    Actually, you can go node-type independent using the `*` selector, but it's obnoxiously bad practice. – Josh Burgess Jan 13 '15 at 19:07
  • 1
    Actually, it does work for different nodes: http://jsfiddle.net/aLhv9r1w/316/. Please update your answer :) – Jamie Barker Jun 01 '15 at 10:44
  • 2
    I had a complex selector, but let's say it's `li#someListItem` and I wanted the node(s) right before it (which is how I interpret "previous") - I don't see how the information you provided can help me express that through CSS. You're just selecting the first n siblings, and assume I know the n. Based on this logic, any selector might do the trick and select the element(s) I need (such as :not() ). – bitoolean Jul 11 '19 at 15:53
  • What? This just selects the first four elements. Not at all what was asked. – corwin.amber Jun 29 '20 at 19:44
12

You could use double negation

SELECTOR:not([SELECTOR]FILTER):not([SELECTOR]FILTER + SELECTOR) { ... }

Replace SELECTOR with either the TAG or .CLASS ( Using #ID is probably too specific ). Replace FILTER with some other :PSUEDO-SELECTOR (I've only tried :hover) or .CLASS (More for toggling through Javascript).

Since the typical usage will probably rely upon hovering (See example that follows)

/* Effect only limited when hovering */
TAG.CLASS:not(TAG.CLASS:hover):not(TAG.CLASS:hover + TAG.CLASS) {}
/* Effect only applied when hovering */
PARENT.CLASS:hover > CHILD.CLASS:not(CHILD.CLASS:hover):not(CHILD.CLASS:hover + CHILD.CLASS) {}

/* Solution */
div.parent:hover > div.child:not(:hover):not(:hover ~ .child)  {
    background-color:red;
    border-radius:1.5em;
}
div.parent:hover > div.child:not(:hover):not(:hover ~ .child) > div {
    background-color:yellow;
}

/* Make pretty (kinda) */
div.parent {
  width:9em;
  height:9em;
  /* Layout */
  display:grid;
  grid-template-columns : auto auto auto;
  grid-template-rows : auto auto auto;
}
div.child {
  /* Dimensions */
  height:3em;
  width:3em;
  /* Layout */
  position:relative;
  /* Cursor */
  cursor: pointer;
  /* Presentation */
  border: 1px black solid;
  border-radius:1.5em;
}
.star {
  /* Dimensions */
  width: 2.5em;
  height: 2.5em;
  /* Placement */
  position:absolute;
  top: 50%;
  left: 50%;
  transform:translate(-50%,-50%);
  /* Geometry */
  -webkit-clip-path: polygon(
    50% 0%,
    63% 38%,
    100% 38%,
    69% 59%,
    82% 100%,
    50% 75%,
    18% 100%,
    31% 59%,
    0% 38%,
    37% 38%
  );
  clip-path: polygon(
    50% 0%,
    63% 38%,
    100% 38%,
    69% 59%,
    82% 100%,
    50% 75%,
    18% 100%,
    31% 59%,
    0% 38%,
    37% 38%
  );
  /* Presentation */
  background-color: lightgrey;
}
div.child:hover {
    /* Presentation */
    background-color:yellow;
    border-radius:1.5em;
}
div.child:hover > div.star {
    /* Presentation */
    background-color:red;
}
<div class="parent">
  <div class="child" href="#"><div class="star"></div></div>
  <div class="child" href="#"><div class="star"></div></div>
  <div class="child" href="#"><div class="star"></div></div>
  <div class="child" href="#"><div class="star"></div></div>
  <div class="child" href="#"><div class="star"></div></div>
  <div class="child" href="#"><div class="star"></div></div>
  <div class="child" href="#"><div class="star"></div></div>
  <div class="child" href="#"><div class="star"></div></div>
  <div class="child" href="#"><div class="star"></div></div>
 </div>
Carel
  • 3,289
  • 2
  • 27
  • 44
7

Overriding the styles of next siblings on hover, so that it looks like only previous siblings have styles added on hover.

ul li {
  color: red;
}

ul:hover li {
  color: blue;
}

ul:hover li:hover ~ li{
  color: red;
}
<ul>
    <li>item 1</li>
    <li>item 2</li>
    <li>item 3</li>
</ul>
meghahere
  • 131
  • 2
  • 9
7

My requirement was to select currently hovered item's previous and next two siblings with the help of @Quentin 's answer I selected previous siblings.

.child{
  width: 25px;
  height: 25px;
}

.child:hover {
    background:blue;
}

 .child:has( + .child:hover) {
  background: yellow;
}

.child:has(+ .child + .child:hover){
  background:green;
}

.child:hover + .child {
  background: red;
}

.child:hover + .child + .child {
  background: magenta;
}
<ul class="parent">
  <li class="child"></li>
  <li class="child"></li>
  <li class="child"></li>
  <li class="child"></li>
  <li class="child"></li>
  <li class="child"></li>
</ul>

To select all previous siblings

.child {
    width: 25px;
    height: 25px;
}

.child:hover {
    background: blue;
}

.child:has(~ .child:hover) {
    background: red;
}
<ul class="parent">
  <li class="child"></li>
  <li class="child"></li>
  <li class="child"></li>
  <li class="child"></li>
  <li class="child"></li>
  <li class="child"></li>
</ul>
Harshil Modi
  • 397
  • 3
  • 8
  • 15
7

Things have changed in 2023. Now there is such selector:

    // 1 item before
    :has(+ .item:hover) {
        ...
    }

If you want to select 3 items before, you do something like:

    // 3 items before
    :has(+ .item:hover),
    :has(+ .item + .item:hover),
    :has(+ .item + .item + .item:hover) {
        ...
    }

See my demo here https://codepen.io/ro31337/pen/YzJbEZv

Roman Pushkin
  • 5,639
  • 3
  • 40
  • 58
  • You can also use item:has(~ item:hover) to change ALL previous siblings before the currently hovered element. – lsblsb Aug 21 '23 at 06:51
6

If you know the exact position an :nth-child()-based exclusion of all following siblings would work.

ul li:not(:nth-child(n+3))

Which would select all lis before the 3rd (e.g. 1st and 2nd). But, in my opinion this looks ugly and has a very tight usecase.

You also could select the nth-child right-to-left:

ul li:nth-child(-n+2)

Which does the same.

kernel
  • 3,654
  • 3
  • 25
  • 33
6

No. It is not possible via CSS. It takes the "Cascade" to heart ;-).


However, if you are able to add JavaScript to your page, a little bit of jQuery could get you to your end goal.
You can use jQuery's find to perform a "look-ahead" on your target element/class/id, then backtrack to select your target.
Then you use jQuery to re-write the DOM (CSS) for your element.

Based on this answer by Mike Brant, the following jQuery snippet could help.

$('p + ul').prev('p')

This first selects all <ul>s that immediately follow a <p>.
Then it "backtracks" to select all the previous <p>s from that set of <ul>s.

Effectively, "previous sibling" has been selected via jQuery.
Now, use the .css function to pass in your CSS new values for that element.


In my case I was looking to find a way to select a DIV with the id #full-width, but ONLY if it had a (indirect) descendant DIV with the class of .companies.

I had control of all the HTML under .companies, but could not alter any of the HTML above it.
And the cascade goes only 1 direction: down.

Thus I could select ALL #full-widths.
Or I could select .companies that only followed a #full-width.
But I could not select only #full-widths that proceeded .companies.

And, again, I was unable to add .companies any higher up in the HTML. That part of the HTML was written externally, and wrapped our code.

But with jQuery, I can select the required #full-widths, then assign the appropriate style:

$("#full-width").find(".companies").parents("#full-width").css( "width", "300px" );

This finds all #full-width .companies, and selects just those .companies, similar to how selectors are used to target specific elements in standard in CSS.
Then it uses .parents to "backtrack" and select ALL parents of .companies,
but filters those results to keep only #fill-width elements, so that in the end,
it only selects a #full-width element if it has a .companies class descendant.
Finally, it assigns a new CSS (width) value to the resulting element.

$(".parent").find(".change-parent").parents(".parent").css( "background-color", "darkred");
div {
  background-color: lightblue;
  width: 120px;
  height: 40px;
  border: 1px solid gray;
  padding: 5px;
}
.wrapper {
  background-color: blue;
  width: 250px;
  height: 165px;
}
.parent {
  background-color: green;
  width: 200px;
  height: 70px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<html>
<div class="wrapper">

  <div class="parent">
    "parent" turns red
    <div class="change-parent">
    descendant: "change-parent"
    </div>
  </div>
  
  <div class="parent">
    "parent" stays green
    <div class="nope">
    descendant: "nope"
    </div>
  </div>
  
</div>
Target <b>"<span style="color:darkgreen">parent</span>"</b> to turn <span style="color:red">red</span>.<br>
<b>Only</b> if it <b>has</b> a descendant of "change-parent".<br>
<br>
(reverse cascade, look ahead, parent un-descendant)
</html>

jQuery Reference Docs:
$() or jQuery(): DOM element.
.find: Get the descendants of each element in the current set of matched elements, filtered by a selector, jQuery object, or element.
.parents: Get the immediately preceding sibling of each element in the set of matched elements. If a selector is provided, it retrieves the previous sibling only if it matches that selector (filters the results to only include the listed elements/selectors).
.css: Set one or more CSS properties for the set of matched elements.

SherylHohman
  • 16,580
  • 17
  • 88
  • 94
  • This has nothing to do with the question. Of course it's possible using JS and you don't even need jQuery for this (`previousElementSibling`). – Fabian von Ellerts Jul 10 '19 at 17:43
  • 1
    @FabianvonEllerts I answered OP's question directly in the first line of my response. As my answer states, it is literally **not possible via CSS**. I then provided ***1*** *possible path forward* to achieve the goal, using a technology (JS | JQuery) that users of CSS might be familiar with and have access to. For example, many WordPress sites also have JQuery, so it is an easy entry point: easy to use, remember, and expand upon. It'd be irresponsible to simply answer *NO*, without providing an alternate way to accomplish the goal. I shared what I learned and used when I had the same question. – SherylHohman Jul 10 '19 at 19:48
  • [`previousElementSibling()`](https://www.w3schools.com/jsref/prop_element_previouselementsibling.asp) for those more familiar with native JS DOM functions could provide *another* non-CSS path forward. – SherylHohman Jul 10 '19 at 19:56
  • I found the other CSS HACKS very interesting, but for my particular use case they either did not work (fell into the caveats category), or were too convoluted. For others that fall into the same circumstance, it is fair to share this easy-to-use method that can work, where the above solutions fail, or would be too difficult to implement/maintain. Many CSS HACKS were shared. This work around was not covered. NONE of the answers use the `+` (non-existent) selector that the OP specifically asked for. Consider this answer a JS "hack". It's here to save someone else time I spent to find a solution. – SherylHohman Jul 10 '19 at 20:16
  • 1
    "_It takes the "Cascade" to heart ;-)._" Well said. You could probably have stopped right there. ;^D – ruffin Jun 18 '20 at 22:01
4

Depending on your exact objective, there is a way to achieve the usefulness of a parent selector without using one (even if one were to exist)...

Say we have:

<div>
  <ul>
    <li><a>Pants</a></li>
    <li><a>Socks</a></li>
    <ul>
      <li><a>White socks</a></li>
      <li><a>Blue socks</a></li>
    </ul>
  </ul>
</div>

What can we do to make the Socks block (including sock colours) stand out visually using spacing?

What would be nice but doesn't exist:

ul li ul:parent {
  margin-top: 15px;
  margin-bottom: 15px;
}

What does exist:

li > a {
  margin-top: 15px;
  display: block;
}
li > a:only-child {
  margin-top: 0px;
}

This sets all anchor links to have 15px margin on the top and resets it back to 0 for those with no UL elements (or other tags) inside LIs.

falsarella
  • 12,217
  • 9
  • 69
  • 115
DynamicDan
  • 425
  • 4
  • 12
4

/* Add a style to all the children, then undo the style to the target 
and sibling children of your target. */

ul>li {
  color: red;
}

ul>li.target,
ul>li.target~li {
  color: inherit;
}
<ul>
  <li>before</li>
  <li class="target">target</li>
  <li>after</li>
  <li>after</li>
</ul>
isherwood
  • 58,414
  • 16
  • 114
  • 157
R-D
  • 566
  • 6
  • 13
  • I think https://stackoverflow.com/a/48952456/1347604 is somewhat the same approach, but this one uses inherit for the other elements which might help keep the focus on the question's literal ask of equivalence for previous sibling – Jasmine Hegman Dec 11 '20 at 14:21
4

I've found the easiest solution. It might only apply based on what you're doing.

Let's say you want to hover on "sibling_2" to change "sibling_1" in the example below:

<div class='parent'>
  <div class='sibling_1'></div>
  <div class='sibling_2'></div>
</div>

Since there's no previous element selector you can simply switch 'sibling_1' and 'sibling_2' around and apply so they look the same.

.parent {
  display: flex;
  flex-direction: row-reverse;
}

Now you can select them like that.

.sibling_1:hover ~ .sibling_2 {
  #your CSS
}
Roma Kim
  • 321
  • 1
  • 8
3

There is no "previous" sibling selector unfortunately, but you can possibly still get the same effect by using positioning (e.g. float right). It depends on what you are trying to do.

In my case, I wanted a primarily CSS 5-star rating system. I would need to color (or swap the icon of) the previous stars. By floating each element right, I am essentially getting the same effect (the html for the stars thus must be written 'backwards').

I'm using FontAwesome in this example and swapping between the unicodes of fa-star-o and fa-star http://fortawesome.github.io/Font-Awesome/

CSS:

.fa {
    display: inline-block;
    font-family: FontAwesome;
    font-style: normal;
    font-weight: normal;
    line-height: 1;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

/* set all stars to 'empty star' */
.stars-container {
    display: inline-block;      
}   

/* set all stars to 'empty star' */
.stars-container .star {
    float: right;
    display: inline-block;
    padding: 2px;
    color: orange;
    cursor: pointer;

}

.stars-container .star:before {
    content: "\f006"; /* fontAwesome empty star code */
}

/* set hovered star to 'filled star' */
.star:hover:before{
    content: "\f005"; /* fontAwesome filled star code */
}

/* set all stars after hovered to'filled star' 
** it will appear that it selects all after due to positioning */
.star:hover ~ .star:before {
    content: "\f005"; /* fontAwesome filled star code */
}

HTML: (40)

JSFiddle: http://jsfiddle.net/andrewleyva/88j0105g/

Andrew Leyva
  • 124
  • 5
3

There isn't, and there is.

If you must place the label before the input, just place the label after the input and keep both the label & the input inside a div, and style the div as following :

.input-box {
  display: flex;
  flex-direction: column-reverse;
}
<div class="input-box">
  <input
   id="email"
   class="form-item"           
   />

   <label for="email" class="form-item-header">                  
   E-Mail*                  
   </label>
</div>

Now you can apply the standard next sibling styling options available in css, and it will appear like you are using a previous sibling styling.

Ron16
  • 445
  • 6
  • 11
3

You can use :has() as following.

.thePrevious:has(+ .theNextSibling)

I used this for fixing overlapping bootstrap modals as follows. Any previous modals will be hidden if there are multiple.

.modal.show.modal--open:has(~ .modal.show.modal--open){
   opacity: 0;
 }
Bahtiyar Özdere
  • 1,818
  • 17
  • 21
3

There is actually no selector that can select the previous sibling in css. But it is possible to use certain tricks. For example, if you want to change the style of the previous element when you hover over any element, you can use this:

<!DOCTYPE html>
<html lang="en">
<head>
  <style>
    .element:has(+ .next-element:hover){
      /* here your style for .element */
    }
  </style>
</head>
<body>
  <div class="container">
    <div class="element"></div>
    <div class="next-element"></div>
  </div>
</body>
</html>

In this situation if you hover over .next-element the style of .element will change as you defined above

2

I needed a solution to select the previous sibling tr. I came up with this solution using React and Styled-components. This is not my exact solution (This is from memory, hours later). I know there is a flaw in the setHighlighterRow function.

OnMouseOver a row will set the row index to state, and rerender the previous row with a new background color

class ReactClass extends Component {
  constructor() {
    this.state = {
       highlightRowIndex: null
    }
  }

  setHighlightedRow = (index) => {
    const highlightRowIndex = index === null ? null : index - 1;
    this.setState({highlightRowIndex});
  }

  render() {
    return (
       <Table>
        <Tbody>
           {arr.map((row, index) => {
                const isHighlighted = index === this.state.highlightRowIndex
                return {
                    <Trow 
                        isHighlighted={isHighlighted}
                        onMouseOver={() => this.setHighlightedRow(index)}
                        onMouseOut={() => this.setHighlightedRow(null)}
                        >
                        ...
                    </Trow>
                }
           })}  
        </Tbody>   
       </Table>
    )
  }
}

const Trow = styled.tr`
    & td {
        background-color: ${p => p.isHighlighted ? 'red' : 'white'};
    }

    &:hover {
        background-color: red;
    }
`;
kyle
  • 527
  • 6
  • 21
2

There is no such selector, but in the DOM API has a pretty read-only property

Node.previousSibling

Dandgerson
  • 81
  • 1
  • 8
2

I fixed this problem by putting my elements in a flexbox and then using flex-direction: column-reverse.

Then I had to invert my elements in the HTML manually (put them in reverse order), and it looked normal and it worked!

<div style="display: flex; flex-direction: column-reverse">
  <a class="element2">Element 2</a>
  <a class="element1">Element 1</a>
</div>
...
<style>
  .element2:hover + element1 {
    ...
  }
</style>
Leo
  • 10,407
  • 3
  • 45
  • 62
tolypash
  • 117
  • 9
1

I had a similar problem and found out that all problem of this nature can be solved as follows:

  1. give all your items a style.
  2. give your selected item a style.
  3. give next items a style using + or ~.

and this way you'll be able to style your current, previous items(all items overridden with current and next items) and your next items.

example:

/* all items (will be styled as previous) */
li {
  color: blue;
}

/* the item i want to distinguish */
li.milk {
  color: red;
}

/* next items */
li ~ li  {
  color: green;
}


<ul>
  <li>Tea</li>
  <li class="milk">Milk</li>
  <li>Juice</li>
  <li>others</li>
</ul>

Hope it helps someone.

Hejar
  • 110
  • 1
  • 3
  • 2
    it's basically the same trick as in older answer from the same thread: https://stackoverflow.com/a/27993987/717732 – quetzalcoatl Sep 16 '19 at 14:42
  • 1
    But this one bothers to explain what it's doing, unlike the other one. – Teepeemm Oct 02 '20 at 00:25
  • @Teepeemm, I agree. I saw that answer, and I skipped over it because there was no good explanation. It was just "look what I did and copy me!" – Bobort Jun 03 '22 at 21:28
1

here is the link for a similar question

CSS select all previous siblings for a star rating

So I post my solution using bits of everyones responses and anyone can use it as reference and possibliy recommend improvements.

// Just to check input value
// Consts
const starRadios = document.querySelectorAll('input[name="rating"]');

// EventListeners
starRadios.forEach((radio) => radio.addEventListener('change', getStarRadioValue));

// Get star radio value
function getStarRadioValue(event) { 
    alert(event.target.value) 
    // Do something with it
};
.star-rating {
  font-size: 1.5rem;
  unicode-bidi: bidi-override;
  direction: rtl;
  text-align: left;
}
.star-rating.editable label:hover {
  cursor: pointer;
}
.star-rating.editable .icon-star:hover,
.star-rating.editable .icon-star:hover ~ .icon-star {
  background-color: #fb2727 !important;
}

.icon-star {
  position: relative;
  background-color: #72747d;
  width: 32px;
  height: 32px;
  display: inline-block;
  transition: background-color 0.3s ease;
}
.icon-star.filled {
  background-color: #fb2727;
}

.icon-star > label {
  display: inline-block;
  width: 100%;
  height: 100%;
  left: 0;
  top: 0;
  position: absolute;
}

.icon-star > label > input[type="radio"] {
  position: absolute;
  top: 0;
  left: 0;
  transform: translateY(50%) translateX(50%);
  display: none;
}
<div class="star-rating editable">
  <span class="icon-star">
    <label>
      <input type="radio" name="rating"  value="5" />
    </label>
  </span>
  <span class="icon-star">
    <label>
      <input type="radio" name="rating" value="4" />
    </label>
  </span>
  <span class="icon-star">
    <label>
      <input type="radio" name="rating" value="3" />
    </label>
  </span>
  <span class="icon-star">
    <label>
      <input type="radio" name="rating" value="2" />
    </label>
  </span>
  <span class="icon-star">
    <label>
      <input type="radio" name="rating"  value="1" />
    </label>
  </span>
</div>
Jackal
  • 3,359
  • 4
  • 33
  • 78
0

For my use case was needed to change previous element style on focus and hover only having 2 items in parent element. to do so used :focus-within and :hover pseudo-classes.

like so selecting whenever focus/hover event occurs

.root-element:hover .element-to-style { background-color: red;} 
.root-element:focus-within .element-to-style { background-color: green;} 
<div class="root-element">
<span class="element-to-style"> TextFocused</span>
<input type="text" placeholder="type To Style"/>

</div>
Nerius Jok
  • 3,059
  • 6
  • 21
  • 27
0

Here's my working solution using only CSS for gold stars (SCSS specifically in this case)

  • I have 5 initially grey stars inside a container div
  • On hover of the container div, I make all the stars gold
  • On hover over the specific star, I make all successor sibling divs grey

Below is svelte code (but can easily be converted into HTML)

<button id="review">
        <div id="star-container">
          <div><Fa icon="{faStar}" /></div>
          <div><Fa icon="{faStar}" /></div>
          <div><Fa icon="{faStar}" /></div>
          <div><Fa icon="{faStar}" /></div>
          <div><Fa icon="{faStar}" /></div>
        </div>
</button>

<style lang="scss">
  #review {
    color: $cool-gray;
    #star-container {
      display: flex;
      &:hover {
        color: $custom-gold;
      }
      div {
        &:hover ~ div {
          color: $cool-gray;
        }
      }
    }
  }
</style>
-1

I had this same problem, while I was trying to change prepend icon fill color on input focus, my code looked something like this:

<template #append>
    <b-input-group-text><strong class="text-danger">!</strong></b-input-group-text>
</template>
<b-form-input id="password_confirmation" v-model="form.password_confirmation" type="password" placeholder="Repeat password" autocomplete="new-password" />

The problem was that I'm using a vue-bootstrap slot to inject the prepend, so even if i change the location still get rendered after the input

Well my solution was to swipe their location, and add custom prepend and used ~ symbol, as css doesn't support previous sibling.

<div class="form-input-prepend">
    <svg-vue icon="common.lock" />
</div>
<b-form-input id="password_confirmation" v-model="form.password_confirmation" type="password" placeholder="Repeat password" autocomplete="new-password" />

Scss style

.form-control:focus ~ .form-input-prepend {
    svg path {
        fill: $accent;
    }
}

So just try to change its position, and if necessary use css order or position: absolute; to achieve what you want, and to avoid using javascript for this kind of needs.

-1

there is a new psudoclass called has() which is useful when you want to select the first previous sibling of an item which a event has occurred. there is a blog post by: Jim Nielsen’s which might be helpful for you.

enter link description here

-4

Though there is no previous CSS selector. I've found a quick and easy method to select one yourself. Here is the HTML markup:

<div class="parent">
    <div class="child-1"></div>
    <div class="child-2"></div>
</div>

In your JavaScript simply do:

document.querySelector(".child-2").parentElement.querySelector(".child-1")

This will first select the parent div and later on select the child-1 div from the child-2 div.

If you are using jQuery you can simply do:

$(".child-2").prev()
The Myth
  • 1,090
  • 1
  • 4
  • 16