Next-sibling combinator should not work with complex selectors

落爺英雄遲暮 提交于 2021-02-05 05:50:28

问题


TL;DR

According to the spec the following should not work but it does:

.a .b + .b {margin-top:20px;}

Details

According to the spec the "Next-sibling combinator" (or "adjacent sibling combinator") should only work for "sequences of simple selectors", which themselves are defined as

... a chain of simple selectors that are not separated by a combinator.

In my example given above, the selector .a .b to the left contains a "descendant combinator" (represented by whitespace) and should therefore not be allowed.

Interestingly, the following does indeed not work at all:

.b + .a .b {margin-top:20px;}

Why does my introductory example work in modern browsers?


回答1:


In the specification you can read:

The next-sibling combinator is made of the "plus sign" (U+002B, +) character that separates two sequences of simple selectors. The elements represented by the two sequences share the same parent in the document tree and the element represented by the first sequence immediately precedes the element represented by the second one.

Nothing is saying that it should only work for "sequences of simple selectors". It's simply saying that the + character separates two sequences of simple selectors and it restricts nothing beyond this so you can have more selectors.

Let's consider the following examples:

.a .b + .b
.b + .b
span.a:not(.b) .b + .b > div

In all of them we have the portion .b + .b which is described by:

the "plus sign" (U+002B, +) character that separates two sequences of simple selectors.


If you read at the start of the specification you will find the generic rule that confirms this:

A selector is a chain of one or more sequences of simple selectors separated by combinators. One pseudo-element may be appended to the last sequence of simple selectors in a selector.

A sequence of simple selectors is a chain of simple selectors that are not separated by a combinator. It always begins with a type selector or a universal selector. No other type selector or universal selector is allowed in the sequence.

A simple selector is either a type selector, universal selector, attribute selector, class selector, ID selector, or pseudo-class.

Basically we can have

Seq_simple_selectors + Seq_simple_selectors Seq_simple_selectors > Seq_simple_selectors

Then inside each Seq_simple_selectors we can have something like:

 div.a.b#id::before

If we consider your example .a .b + .b you have 3 sequences and in each sequence only one simple selector.

You second example is also fine and working if you have the correct HTML that goes with:

.b + .a .b {
  background: red;
  height: 20px;
}
<div class="b"></div>
<div class="a">
  <div class="b"></div>
</div>

What is invalid is to have something like this .b + > .a. In this case we don't have:

the "plus sign" (U+002B, +) character that separates two sequences of simple selectors.

But we have a separation between a sequence of simple selector and a combinator selector.




回答2:


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>


来源:https://stackoverflow.com/questions/58804827/next-sibling-combinator-should-not-work-with-complex-selectors

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!