Andy Mangold
Andy Mangold

Reputation: 121

CSS Select a Chain of Immediate Siblings

I've got a project wherein I have no control whatsoever over the markup. I'm looking for a way to select every instance of 'class2' that immediately follows an instance of 'class1'. The following strategy works, but in some cases there are over 20 instances of 'class2' in a row and I'd prefer to avoid that huge mess in my code.

.class1 + .class2,
.class1 + .class2 + .class2,
.class1 + .class2 + .class2 + .class2,
.class1 + .class2 + .class2 + .class2 + .class2,
.class1 + .class2 + .class2 + .class2 + .class2 + .class2
// etc.
{
  // Applied Styles
}

...to style the following

<div class="class1"></div>
<div class="class2">Style Me!</div>
<div class="class2">Style Me!</div>
<div class="class2">Style Me!</div>
<div class="class2">Style Me!</div>
<p>Blah blah blah</p>
<div class="class2">DO NOT STYLE ME</div>
<div class="class2">DO NOT STYLE ME EITHER</div>

Upvotes: 9

Views: 798

Answers (4)

gotohales
gotohales

Reputation: 3695

The general sibling combinator might get what you need. It would look like this:

.class1 ~ .class2 {
/* Styles */
}

You can find more info on it here.

Here is an example as well http://jsbin.com/arorij/1/edit

EDIT

This may work for your case, using two rules together like so:

.class1 ~ .class2 + .class2 {
  color: red;
}

.class1 + .class2 {
  color: red;
}

Upvotes: 3

Tracy Fu
Tracy Fu

Reputation: 1662

Here's a stab in the dark using the new :not selector @spudley suggested. It looks like it has okay support: http://caniuse.com/#search=%3Anot. I hope the syntax is right. Edits welcome.

And most of this was taken from @mookamafoob's solution. I didn't submit an edit in case @mookamafoob was averse to using the :not selector prematurely.

http://jsbin.com/umivas/6/edit

.class1 ~ .class2 + .class2 {
  color: red;
}

.class1 + .class2 {
  color: red;
}

.class1 ~ *:not(.class2) ~ .class2 {
  color: inherit;
}

Edit: Sorry for the lack of explanation. The last part attempts to select any element that is a sibling of .class1 that doesn't have .class2 and resets all subsequent siblings with .class2 back to their original state. This could be kind of insane depending on how many styles you're applying.

Upvotes: 4

Spudley
Spudley

Reputation: 168665

My suggestion would be to simply set the style for .class1 ~ .class2, and then override it back to the previous value for p ~ .class2.

It's not a perfect solution, because the second selector there can't know what it's overriding back to; you just have to set it to what you expect the defaults should be. But it should be workable.

Another idea I had was to use the CSS not selector.

With that, you can switch to the easier ~ to select the group of all the relevant class2 elements, but use not and ~ to filter out the ones which follow the <p> tag.

eg:

.class1 ~ :not(p) ~ .class2 

Unfortunately, I don't think this idea will work as shown; the use of the ~ here makes for some combinations we don't want that will be selected regardless of the not. It may be possible to come up with a not selector that will work, but I haven't managed to devise it in the time I've spent trying now.

Upvotes: 3

Sean Redmond
Sean Redmond

Reputation: 4114

Maybe you need to flip the logic around? Can you write a rule for a .class2 that follows a .class1 or a .class2 that follows a .class2?

.class1 + .class2, .class2 + .class2 {
    ...
}

That rule would not apply to that last div in your example since it follows neither.

Upvotes: 0

Related Questions