I am seeing a lot of people using pseudo-classes to style elements other that the target of the pseudo-classes, and instead using the pseudo-class as a conditional. It looks like this:
input:checked + div{...}
I keep trying to find ANYTHING that provides some insight into how this system works. I'm really hoping that there is a way to move up in the DOM tree, and not just sideways and down.
So what would I search to find more information on this subject, what is this principle called?
What is the basic usage for this syntax?
So what would I search to find more information on this subject, what is this principle called?
What is the basic usage for this syntax?
There is actually nothing special about the given selector as a whole. It does however make use of a number of individual concepts to build a complex selector that does something pretty nifty.
The +
symbol that you see is called a "combinator"; a combinator expresses a relationship between two elements (that each have their own selectors). The +
combinator for example expresses an adjacent sibling relationship between the input
and the div
:
<!-- Doesn't matter what the parent element is, as long as there is one -->
<div>
<input type="checkbox" checked> <!-- input:checked -->
<div></div> <!-- div -->
</div>
The :checked
pseudo-class refers to a form element that is checked, in this case an input
element. This pseudo-class is dynamic, in that selecting or deselecting the element will toggle the pseudo-class, but I've included the checked
attribute in the markup for the sake of illustration.
Putting them together you have input:checked + div
, which selects any div
that directly follows a checked input
element. It will not select any other div
elements, and in particular it will not select those that directly follow unchecked input
elements. This technique is collectively known as the checkbox hack — the reason it's a hack is because it often abuses a checkbox control for use cases it was never intended for.
The reason that it targets the div
and not the input
is because div
is the subject of the selector. This is always the rightmost element in a complex selector; any other selectors that are linked to it by combinators are simply there for context. In fact, something like this would be known in CSS1 as a "contextual selector" (although +
and :checked
didn't exist in CSS1), and this is referenced again in the informative overview of the latest specification.
So, in short, what makes this so clever is the fact that you can attach dynamic pseudo-classes to any part of a selector, and then you can use one or more combinators to link that element to an entirely different one which will end up as the subject of your selector.
Now, the answer to this:
I'm really hoping that there is a way to move up in the DOM tree, and not just sideways and down.
Is that, unfortunately, there isn't a combinator that can do this for you, since combinators only exist for moving down (descendant, child) and sideways (next-sibling, following-sibling). In recent history, a new feature was proposed that would allow you to designate any part of a complex selector as the subject of that selector, eliminating the need for a parent or preceding-sibling combinator:
ul > li /* Targets the li */
!ul > li /* Targets the ul */
But that has fallen out of favor in a survey held by the working group. See Latest on CSS parent selector for a new proposal called a relational selector — the main reason for which is because it is far more versatile than even the aforementioned subject selector (and of course it also eliminates the need for new combinators).
There is no parent selector yet.
What you code shows is when something is selected (parent) change something (child).
This special way of using input
fields and the :checked
pseudo class is sometimes referred to as “checkbox hack”.
And while you can not (currently) move “upwards” in the DOM with CSS selectors or select following elements that are not siblings (same parent element), using checkboxes still offers you quite some flexibility – because you can place the input
element itself right in front of the element(s) you want to target, and use a label
to trigger change of the checkbox state by clicking on the content of the label … and that label can be placed (nearly) anywhere in your document. (Although you might be out of luck then if you want to change the formatting of the label itself according to the checkbox state.)