Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the logic behind sibling selectors * + * and * ~ *?

Tags:

For this question I'm using the following markup:

<body>
    <p>1</p> <!-- Paragraph 1 -->
    <p>2</p> <!-- Paragraph 2 -->
    <p>3</p> <!-- Paragraph 3 -->
</body>

From the Selectors Level 3 specification, the following selector rules apply:

*        any element
E + F    an F element immediately preceded by an E element
E ~ F    an F element preceded by an E element

Based on this, the following should occur:

body + * { } /* Selects nothing as no elements precede body */
body ~ * { } /* As above. */
p + *    { } /* Selects Paragraph 2 and Paragraph 3 as these are preceded by p */
p ~ *    { } /* As above. */
* + *    { } /* As above. */
* ~ *    { } /* As above. */

False!

* + * and * ~ * are somehow able to select Paragraph 1 along with 2 and 3! Paragraph 1 isn't preceded by anything, so should be impossible to access:

body + * { background: #000; }
body ~ * { background: #000; }
p ~ *    { color: #f00; }
p + *    { font-weight: bold; }
* + *    { text-decoration: underline; }
* ~ *    { font-style: italic; }

Result:

Result example; paragraph 2 and 3 are red and all paragraphs are italic and underlined

As you can see, paragraph 1 isn't preceded by the body or a phantom p, yet it is apparently preceded by something. It should have no custom styling applied to it at all, yet is somehow affected by those last two selectors. What is the logic behind this?

JSFiddle example.

like image 995
James Donnelly Avatar asked May 22 '13 15:05

James Donnelly


People also ask

What are sibling selectors?

The adjacent sibling selector is used to select an element that is directly after another specific element. Sibling elements must have the same parent element, and "adjacent" means "immediately following".

How are general sibling selectors used?

HTML, CSS and JavaScript The CSS general sibling selector is used to select all elements that follow the first element such that both are children of the same parent.

Which character is used in an adjacent sibling selector?

The '+' Symbol This is Adjacent Sibling Selector. It selects all elements that are the adjacent siblings of a specified element. Sibling elements must have the same parent element, and “adjacent” means “immediately following”.


3 Answers

* + * Styles any element that is an immediate sibling of any element starting from the document root - Since the <head> is actually an immediate preceding sibling of the body (despite not being visible in your code) this selector targets the body and the last two paragraphs, since the first paragraph isn't immediately following another sibling element. All three paragraphs happened to be underlined due to the nature of text-decoration on block-level descendants in the normal flow.

* ~ * This is basically the same thing as above, except using the general sibling combinator .. it styles downstream sibling element(s) that appear after the <head> regardless of whether they're immediate siblings or not. Since the <body> is the only sibling, this has the same effect as the above selector. The first paragraph is italicized due to inheritance.

p ~ * selects a sibling element that is following a <p> which in your example is the last two paragraphs. p + * styles any element that is immediate sibling of a paragraph, which would also be the last two <p> elements.

like image 114
Adrift Avatar answered Oct 12 '22 14:10

Adrift


They are not applied to the first paragraph actually. To demonstrate this, let's change the stylesheet a bit:

* + *    { border-right: solid red }
* ~ *    { border-left: solid black; }

demo

fiddle

They are both applied to the "body" element which is in fact preceded by "head".

like image 45
Simon Perepelitsa Avatar answered Oct 12 '22 13:10

Simon Perepelitsa


That's an error in your test case. As you would expect, none of the selectors match the first paragraph, but the styling from the body cascades to the paragraphs!

Both * + * and * ~ * match body as it is preceded by a head tag. Thus, it receives text-decoration:underline and font-style:italic. That explains why all of the paragraphs are both underlined and italicised.

like image 43
Mattias Buelens Avatar answered Oct 12 '22 13:10

Mattias Buelens