Hamty Hamty - 3 months ago 6
CSS Question

Can I select an element that's not immediately after another, e.g. :not(.foo + .bar)?

Is there a way to have a

:not(.foo + .bar)
selector? Or do I have to use a separate selector to cancel out the effects of
.foo + .bar
?

Answer

It's worth noting that :not(.foo + .bar) is valid in Selectors 4, and implementations are on their way. Having said that, due to the nature of the adjacent sibling combinator + (and similarly the child combinator >), there is a Selectors 3 equivalent, although you will need a list of up to three complex selectors:

:first-child, :not(.foo) + *, .foo + :not(.bar)

But this is a direct conversion that accounts for elements that are not .bar. More likely, you just want to match any .bar that's not directly preceded by a .foo. In that case, it gets even simpler:

.bar:first-child, :not(.foo) + .bar

And you can pick and choose further depending on your needs:

  • If not being preceded by a .foo means .bar becomes the first child, you can just use .bar:first-child.
  • If .bar is guaranteed to have a preceding sibling, you can just use :not(.foo) + .bar.

If you need to account for both possibilities, then listing both as shown above will do just fine.

Note that the .foo and .bar selectors don't necessarily have to be different. You can match any .bar that's not immediately preceded by another .bar with the exact same technique.

Comments