102

This selects all <B> tags directly preceded by <A> tags:

A+B {
    /* styling */
}

What is the selector for all <A> tags directly followed by <B> tags?

Here's sample HTML fitting my question:

<a>some text</a>
<b>some text</b>
Trojan
  • 2,216
  • 27
  • 40
Mostafa Farghaly
  • 1,297
  • 2
  • 9
  • 15
  • 3
    Pease give us a DOM example how `A` and `B` are related. – Gumbo Jul 15 '09 at 16:38
  • 5
    They are related in that they are siblings, and B is followed by A. The OP wants to select all `b`s which are followed by `a`s, similar to the `a+b` where you can select all `b`s that are preceded directly by `a`. – Anthony Apr 07 '12 at 02:38
  • 2.5 years later, is there any update to this answer? I'm also looking to target a followed by b. – chovy Feb 09 '18 at 16:49

4 Answers4

56

Do you mean to style A given that it has a B element directly inside or followed? Like this:

<A>
    <B>
    </B>
</A>

// OR

<A>
</A>
<B>
</B>

You can't do such a thing in CSS (yet). Eric Meyer states that this kind of selector has been discussed quite a few times on the CSS mailing list, and isn’t doable. Dave Hyatt, one of the core WebKit developers, comments with a good explanation of why it can’t be done.

Check out: Shaun Inman's blog post and the comment by Eric Meyer.
David Hyatt weighs in, too.

Nick Presta
  • 27,478
  • 6
  • 54
  • 75
33

You can’t in css.

Edit: To be a bit more helpful, if you use for example jQuery (a JavaScript library), you can use .prev().

bdesham
  • 14,616
  • 11
  • 78
  • 119
jeroen
  • 90,003
  • 21
  • 112
  • 129
20

You can ONLY do the converse: This selects all tags directly preceded by tags.

This is logically equivalent to your request.

I often use this to style a row of many checkboxes with labels

CSS:

label+input {
    margin-left: 4px;
}

DOM:

<input id="a" name="a" type="checkbox"/><label for="a">...</label>
<input id="b" name="b" type="checkbox"/><label for="b">...</label>
<input id="c" name="c" type="checkbox"/><label for="c">...</label>
Marco Marsala
  • 2,197
  • 5
  • 23
  • 37
  • 3
    I think you meant to type "input+label" in the CSS so that the margin-left is applied to the label. – CAK2 Sep 10 '19 at 04:30
  • 3
    @CAK2 - I think he meant it right. By doing `label+input` the margin is applied to all `input` elements **starting from the second one**. It is a creative way to create space among them but not at the beginning or at then end of the row. In this case, it is equivalent to `input:not(:first-child)`. – David Mar 12 '20 at 21:18
8

Although it's not very handy, nowadays you could achieve this behavior by reversing the order of your elements both when you generate the HTML and by applying the CSS rules: display: flex and flex-direction: column-reverse

ul {
  display: flex;
  flex-direction: column-reverse;
}

.b ~ .a {
  color: red;
}
<ul>
    <li class="a">A 3</li>
    <li class="c">C 2</li>
    <li class="c">C 1</li>
    <li class="b">B 1</li>
    <li class="a">A 2</li>
    <li class="a">A 1</li>
</ul>

Also, if you have 2 or more inline elements, you could achieve it by applying float: right, as they will be displayed in reverse order:

ul {
  float: left;
  list-style-type: none;
}

li {
  float: right;
}

li:not(:first-child) {
  margin-right: 20px;
}

.b ~ .a {
  color: red;
}
<ul>
    <li class="a">A 3</li>
    <li class="c">C 2</li>
    <li class="c">C 1</li>
    <li class="b">B 1</li>
    <li class="a">A 2</li>
    <li class="a">A 1</li>
</ul>
Mihai Matei
  • 23,635
  • 4
  • 32
  • 50