The new name for "sequences of simple selectors" is compound selector. The definitions of compound selector and combinator, and many other terms, in selectors-4 are much clearer than the ones in selectors-3, to such an extent that I no longer recommend using selectors-3 as a reference when trying to understand selector syntax:
A compound selector is a sequence of simple selectors that are not separated by a combinator, and represents a set of simultaneous conditions on a single element.
A combinator is a condition of relationship between two elements represented by the compound selectors on either side.
This should greatly reduce the confusion that might have motivated your question, so I will be using the new name exclusively in my answer.
In your first example, the +
combinator appears between two compound selectors, each containing a single simple selector .b
. In other words, .b + .b
is not a compound selector... because it's two compound selectors and a combinator. Your first example is a valid complex selector consisting of three compound selectors and two combinators.
There is no limit to how many compound selectors a valid complex selector can contain, as long as between every two compound selectors is a combinator and not some unexpected token. This implies that a complex selector can, indeed, consist of only one compound selector, and no combinators. These three examples are valid complex selectors (using the notation from the selectors-4 grammar):
<complex-selector> = <compound-selector>
<complex-selector> = <compound-selector> <combinator> <compound-selector>
<complex-selector> = <compound-selector> <combinator> <compound-selector> <combinator> <compound-selector>
Also keep in mind that a complex selector that doesn't match anything can still be valid.
On that note, the reason .b + .a .b
doesn't appear to work is because it has a different meaning to .a .b + .b
, and your HTML doesn't match the criteria spelled out by that complex selector.
.a .b + .b
means
Match any .b
that is the next sibling of another .b
that is a descendant of an .a
.
.b + .a .b
means
Match any .b
that is a descendant of an .a
that is the next sibling of another .b
.
Notice that the other .b
is the previous sibling of a different element in each context. If your HTML satisfies one but not the other, then it will only match the one and not the other. However, the following fragment will satisfy both (and therefore match both):
.a .b + .b { color: red; }
.b + .a .b { font-style: italic; }
code { display: block; }
<div class="b"></div>
<div class="a">
<code class="b">.b</code>
<code class="b">.b + .b</code>
</div>