Web_Designer
Web_Designer

Reputation: 74520

Is there such a thing as an "all inclusive sibling" CSS selector?

My HTML:

<p>Doggies</p>
<p class="green_guys">Froggies</p>
<p>Cupcakes</p>
<p>Piggies</p>

An all inclusive sibling selector (as I wish it to be), when used to select green_guys' siblings, would select the doggies cupcakes and piggies.

Other Selectors:

The + selector (a.k.a. adjacent sibling selector) would only select the cupcakes:

.green_guys + p {
    /* selects the <p> element that immediately follows .green_guys */
}

The ~ selector (a.k.a. general sibling selector) would only select the cupcakes, and piggies:

.green_guys ~ p {
    /* selects all <p> elements that follow .green_guys */
}

Upvotes: 36

Views: 19043

Answers (4)

Jacopo Pace
Jacopo Pace

Reputation: 492

I actually found 3 ways to do this:

Solution 1

.parent > p:not(.green_guys) {
  text-decoration: line-through; /* or whatever you like */
}

Demo: https://jsbin.com/cafipun/edit?html,css,output

PROS: quick and easy.

CONS: you need to know the parent selector (so that's not a super portable solution).

Solution 2

p ~ p:not(.green_guys),
p:first-child:not(.green_guys) {
  text-decoration: line-through; /* or whatever you like */
}

Demo: https://jsbin.com/seripuditu/edit?html,css,output

PROS: there is no need to know the parent selector (it can be very good to be used in generic cases).

CONS: it risks to be too generic (be careful, for example, if you have other p around your HTML!).

Solution 3

Small variant of the Solution 2 (to avoid the CONS). In this case you specify the sibling selector to get a more specific context.

p.siblings ~ p:not(.green_guys),
p.siblings:first-child:not(.green_guys) {
  text-decoration: line-through; /* or whatever you like */
}

Demo: https://jsbin.com/hakasek/edit?html,css,output

PROS: it is a portable solution, there is no need to know the parent selector (it can be very good in generic cases) and there is no worry to have conflict with other elements.

CONS: all siblings have to be well defined (with a class or an attribute for example).

Upvotes: 0

Blender
Blender

Reputation: 298106

Not that I am aware of. There isn't a siblings selector either.

This might work, though:

#parent_of_green_guys > p:not(.green_guys) {
  foo: bar;
}

Or if you aren't looking for ps with class attributes:

#parent_of_green_guys > p:not([class]) {
  foo: bar;
}

Upvotes: 2

Brian F
Brian F

Reputation: 1660

My scenario was a little different but I wanted to select siblings of an input element to display one while it was active and another if it was left invalid.

My html was like this and I was unable to select the invalid text.

<input name="importantAnswer">
<div class="help-text"></div>
<div class="invalid-text"></div>

I was able to get around it by embedding the siblings in an adjacent one and using child selectors on that.

<input name="importantAnswer">
<div class="messages">
   <div class="help-text"></div>
   <div class="invalid-text"></div>
</div>


.help-text, .invalid-text {
   visibility:hidden;
}

.input:active +.messages > .help-text {
   visibility:visible;
}

.input.invalid:visited +.messages > .invalid-text {
   visibility:visible;
}

And it worked.

Upvotes: 1

BoltClock
BoltClock

Reputation: 723438

There is no sibling combinator that looks backward or around, only the adjacent and general sibling combinators that look forward.

The best you can do is determine a way to limit selection only to these p elements with the same parent, and then select the p children that are :not(.green_guys). If the parent element has an ID of #parent, for example, you can use this selector:

#parent > p:not(.green_guys) {
    /* selects all <p> children of #parent that are not .green_guys */
}

However the above will still match your p elements even if none of them have the class. It is currently not possible to select the siblings of an element only given the existence of said element (which is the purpose of a sibling combinator — to establish a relationship between two sibling elements).


Selectors 4's :has() will hopefully rectify this without the need for a preceding-sibling combinator, resulting in the following solution:

p:has(~ .green_guys), .green_guys ~ p {
    /* selects all <p> elements that are siblings of .green_guys */
}

This will not match anything if none of the children of the parent element have the class.

Upvotes: 22

Related Questions