1

I'm trying to highlight the label behind the first unchecked checkbox on the entire page made up by something like this (omitted the extra html in between the div tags for clarity):

.challenges input[type="checkbox"]:not(:checked)~label {
  color: lime;
}
<div class="challenges">
  <input type="checkbox">
  <label for="">test 01</label>
  <input type="checkbox">
  <label for="">test 02</label>
  <input type="checkbox">
  <label for="">test 03</label>
</div>
<div class="challenges">
  <input type="checkbox">
  <label for="">test 01</label>
  <input type="checkbox">
  <label for="">test 02</label>
  <input type="checkbox">
  <label for="">test 03</label>
</div>
<div class="challenges">
  <input type="checkbox">
  <label for="">test 01</label>
  <input type="checkbox">
  <label for="">test 02</label>
  <input type="checkbox">
  <label for="">test 03</label>
</div>
<div class="challenges">
  <input type="checkbox">
  <label for="">test 01</label>
  <input type="checkbox">
  <label for="">test 02</label>
  <input type="checkbox">
  <label for="">test 03</label>
</div>

But that checks all the checkboxes which are net checked. I've been trying with first-of-type etc but that didn't work out.

Kris van der Mast
  • 16,343
  • 8
  • 39
  • 61
  • 1
    So you want just the first unchecked checkbox checked, or the first unchcked checkbox per div? – j08691 Nov 06 '18 at 15:12
  • Node - You should put the `` elements **inside** the ` – vsync Nov 06 '18 at 15:13
  • 1
    `~` is the combinator for _all_ following siblings, if you just want the immediate one, that would be `+` instead. _“behind the first unchecked checkbox on the entire page”_ - that isn’t possible with the structure you have. While you could “reset” the color for all labels that come after a checkbox that is itself a sibling of a checked one, this only works for siblings - and with other grouping div elements in between, they aren’t all siblings to begin with. – misorude Nov 06 '18 at 15:14
  • linked - [https://stackoverflow.com/questions/8828608/css-select-the-first-adjacent-sibling](https://stackoverflow.com/q/8828608/104380) – vsync Nov 06 '18 at 15:15
  • @vsync while that frees you from having to put the `for` attribute on them to specify the associated input field, you would then not be able to select the label based on the checked status of the checkbox any more, for that it has to be a sibling following the input. – misorude Nov 06 '18 at 15:15
  • @misorude - I do this all the time. you just need to put your string inside an element (like ``) which comes *after* the ``. it's a very common practice for almost a decade actually. (see custom-styled checkboxes) – vsync Nov 06 '18 at 15:16
  • @vsync yes, if you introduce an additional element of course it works. But that wasn’t what you said in your comment initially … (Plus it doesn’t change anything about the actual problem they are trying to solve here.) – misorude Nov 06 '18 at 15:24
  • @j08691 I'm trying to highlight the first checkbox on the page which is unchecked to indicate that this is the best next challenge of all to tackle. – Kris van der Mast Nov 06 '18 at 16:56
  • @misorude I can change the html to some point. Just have to make sure the vue.js parts still keep working. Was hoping to find a CSS only way to indicate the label behind the first unchecked checkbox instead of going for a JavaScript approach and add extra fluff which might not be needed. If there's a way with CSS only with some reshuffling or adding some html element to the above please provide it. – Kris van der Mast Nov 06 '18 at 16:59
  • @vsync if you have a great answer with adding the span element I'm all ears. – Kris van der Mast Nov 06 '18 at 17:00

3 Answers3

2

[From comments] Was hoping to find a CSS only way to indicate the label behind the first unchecked checkbox instead of going for a JavaScript approach and add extra fluff which might not be needed. If there's a way with CSS only with some reshuffling or adding some html element to the above please provide it.

Only possible if they are all on the same level, if the multiple grouping DIVs were reduced to just one, so that they all have the same parent.

Then you can set the color for the one checkbox immediately following an unchecked checkbox, and reset it for every label behind a checkbox that is a sibling following the unchecked one ...

.challenges input[type="checkbox"]:not(:checked) + label {
  color: lime;
}

.challenges input[type="checkbox"]:not(:checked) ~ input[type="checkbox"] + label {
  color: #000;
}
<div class="challenges">
  <input type="checkbox">
  <label for="">test 01</label>
  <input type="checkbox">
  <label for="">test 02</label>
  <input type="checkbox">
  <label for="">test 03</label>
  <input type="checkbox">
  <label for="">test 01</label>
  <input type="checkbox">
  <label for="">test 02</label>
  <input type="checkbox">
  <label for="">test 03</label>
  <input type="checkbox">
  <label for="">test 01</label>
  <input type="checkbox">
  <label for="">test 02</label>
  <input type="checkbox">
  <label for="">test 03</label>
  <input type="checkbox">
  <label for="">test 01</label>
  <input type="checkbox">
  <label for="">test 02</label>
  <input type="checkbox">
  <label for="">test 03</label>
</div>
misorude
  • 3,381
  • 2
  • 9
  • 16
  • This looks awesome. Going to try it out with a surrounding div as I need to keep things like they are now as besides challenges I also have ambitions. – Kris van der Mast Nov 08 '18 at 10:19
0

// get all checkboxes 
var firstUncheckedInput = document.querySelectorAll('.challenges input[type="checkbox"]')[0];

firstUncheckedInput.classList.add('firstCheckbox');
.challenges > label{ 
  display:flex; 
  align-items: center;
} 

.challenges .firstCheckbox:not(:checked) + span {
  color: red;
}
<fieldset class="challenges"> 
  <label>
     <input type="checkbox">
     <span>test 1</span>
  </label>
  <label>
     <input type="checkbox">
     <span>test 2</span>
  </label>
  <label>
     <input type="checkbox">
     <span>test 3</span>
  </label>
</fieldset>
<br>
<fieldset class="challenges"> 
  <label>
     <input type="checkbox">
     <span>test 4</span>
  </label>
  <label>
     <input type="checkbox">
     <span>test 5</span>
  </label>
  <label>
     <input type="checkbox">
     <span>test 6</span>
  </label>
</fieldset>
vsync
  • 118,978
  • 58
  • 307
  • 400
  • I'm looking for a CSS only way if possible. Also it should change to the next unchecked checkbox once all the ones before get checked. – Kris van der Mast Nov 07 '18 at 06:14
  • @KrisvanderMast - there is none and you did not specify you want a *css-only* solution in the **title** nor in the question's **description**. I have devoted my time for you and it is your duty not to waste other's time and be absolutely clear when asking questions – vsync Nov 07 '18 at 07:56
  • You don't have to use *javascript* if you have control over the HTML, simply give a class to the first `input` element – vsync Nov 07 '18 at 08:48
  • I added it as the only tag [css]. I updated the title to make it more clear. I don't consider your time as a waste. You tried to help out and that's appreciated by me and the rest of the community. – Kris van der Mast Nov 08 '18 at 09:30
0

I was facing the same problem and was able to extend @misorude's excellent answer by adding display: inline-block and specifying an explicit width for both the enclosing <div> and the individual <label> elements. em-based width specifications seem to work best to accommodate the width of the actual checkbox while still providing flexibility with different font sizes. I'm not saying that this is necessarily a recommended way of solving this in CSS, but if you absolutely must, this did the trick for me. I only tested with Chrome, so YMMV.

<html>
 <head>
  <style>
   .steps
   {
    font-family: '.AppleSystemUIFont';
    font-size: 17px;
    font-weight: normal;
    width: 37em;
    color: #777;
   }
   .steps input[type="checkbox"]:not(:checked) + label
   {
    color: black;
    font-weight: bold;
   }
   .steps input[type="checkbox"]:not(:checked) ~ input[type="checkbox"] + label
   {
    color: #777;
    font-weight: normal;
   }
   .step
   {
    display: inline-block;
    width: 35em;
   }
  </style>
 </head>
 <body>
  <div class="steps">
   <input type="checkbox">
   <label class="step" for="">Create an immutable cache class</label>
   <input type="checkbox">
   <label class="step" for="">Use the cache in a naive/straightforward way</label>
   <input type="checkbox">
   <label class="step" for="">Hide the passing of state (non-monadic)</label>
   <input type="checkbox">
   <label class="step" for="">Simplify by using monadic methods</label>
   <input type="checkbox">
   <label class="step" for="">Incorporate state into the original return type</label>
  </div>
 </body>
</html>
raner
  • 1,175
  • 1
  • 11
  • 21