The plus sign (+
) is for selecting the next sibling.
Is there an equivalent for the previous sibling?
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.
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; }
.parent:hover a
style.
display
of the contender
Selectors level 4 proposes :has()
(previously the subject indicator !
) which will, one day, allow you to select a previous sibling with:
previous:has(+ next) {}
… but at the time of writing browser support is practically non-existent.
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 up to date browser support chart in the answer.
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.
STEPS
Make the ul a flex container. ul { display: flex; }
Reverse the order of siblings in the mark-up.
Use a sibling selector to target Element A (~ or + will do) . li:hover + li { background-color: red; }
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; }
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
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; }
Using the flex order
property to construct a previous sibling selector
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:
Select the preceding sibling of an element in CSS using selectors
CSS: select previous sibling
CSS select previous sibling
Previous adjacent selector in CSS
Select previous siblings on hover
CSS selector to get preceding sibling
Change color of sibling elements on hover using CSS
How to select the previous sibling using selenium css syntax
CSS Selector for selecting an element that comes BEFORE another element?
How to add styling to active input's previous sibling using CSS only
CSS selector for next and previous elements
How to affect other elements when a div is hovered
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/
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.
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
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, and demonstrating direction: rtl
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.
y ~ x
could solve my problem
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 <root><x/><y/></root>
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...)
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 }
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.
.parent a:not(.parent a.active ~ a, a.active, .parent :first-child) { color: red }
to color only the second child.
+ 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; }
?
selector!
selector~
selector+
selector
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!
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!
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!
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%; }
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; }
The oranges elements are the previous sibling li selected using li:nth-child(-n+4)
2
3
6
7
8
9
Limitations
You can't select previous elements based on the classes of the next elements
This is the same for pseudo classes
:nth-child(-n+4)
?
: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
*
selector, but it's obnoxiously bad practice.
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() ).
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; }
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-width
s.
Or I could select .companies
that only followed a #full-width
.
But I could not select only #full-width
s 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-width
s, 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; }
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.
previousElementSibling
).
previousElementSibling()
for those more familiar with native JS DOM functions could provide another non-CSS path forward.
+
(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.
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 li
s 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.
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; }
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.
/* 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; }
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/
+
or ~
selectors strikes me as the cleanest work around.
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;
}
`;
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; }
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.
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:
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 }
I had a similar problem and found out that all problem of this nature can be solved as follows:
give all your items a style. give your selected item a style. 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.
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; }
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;}
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.
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>
Success story sharing