Luke Cottingham Luke Cottingham - 24 days ago 10
CSS Question

CSS Target Selection with + and ~ combinators

I'm struggling to get the following code to target correctly. Can someone help me resolve and finish this issue?

I have a star rating set of inline radio buttons. It's annoying but each radio field has to wrapped in a

<div class="option">
. My target behaviour is:

1) When a radio button is selected (i.e value number 4), all previous labels are targeted and appropriately colored.

2) When hovering, the css overrides the checked behaviour and styles all labels before the input being hovered on.

I had it working without each input being wrapped in the
.option
tag however, as it is a requirement I can't get it to work with the
option
tag.

--

So, I've simplified the code.

Where this would work correctly....



label {
font-size: 20px;
}
input[type*="radio"]:checked + label {
color: blue;
}

input[type*="radio"]:checked + label ~ input[type*="radio"] + label {
color: red;
}

<div>
<input type="radio" id="q1" name="radio" ><label for="q1">1</label>
<input type="radio" id="q2" name="radio" ><label for="q2">2</label>
<input type="radio" id="q3" name="radio" checked><label for="q3">3</label>
<input type="radio" id="q4" name="radio"><label for="q4">4</label>
<input type="radio" id="q5" name="radio"><label for="q5">5</label>
</div>





How do I make the following work with the exact same behaviour as above???



label {
font-size: 20px;
}
.option {
display: inline-block;
}
input[type*="radio"]:checked + label {
color: blue;
}

.option > input[type*="radio"]:checked + label ~ .option > input[type*="radio"] + label {
color: red;
}

<div class="container">
<div class="option">
<input type="radio" id="q1" name="radio"><label for="q1">1</label>
</div>
<div class="option">
<input type="radio" id="q2" name="radio"><label for="q2">2</label>
</div>
<div class="option">
<input type="radio" id="q3" name="radio" checked><label for="q3">3</label>
</div>
<div class="option">
<input type="radio" id="q4" name="radio"><label for="q4">4</label>
</div>
<div class="option">
<input type="radio" id="q5" name="radio"><label for="q5">5</label>
</div>
</div>




Answer Source

As of the current state of CSS, this cannot be done without the aid of JavaScript.

Will it ever be possible? Well, yeah.


Pseudo-class :has()

The Selectors Level 4 Editor's Draft (from August 23 2017) includes a :has() pseudo-class which would solve this issue.

Something along the lines of...

.option:has(input:checked) ~ .option > label {
    color: red;
}

...should select labels coming after a selected option.

As per this great answer:

this is still not supported by any browser.


As BoltClock has beautifully mentioned in the comments, the 'subject' selector was dropped (as can be seen from this awesome answer).

For the sake of completion, though, I'll keep some of my original answer:

On the same draft (not the same!) they introduced the 'subject' of the selector ($) which determines which part of the selector to apply the propeties to. See this other great answer. However, that has now been dropped.