htmlcsscss-selectors

CSS :not selector - Warning: Missing a comma between function arguments


I have this CSS:

.form-group input[type=checkbox]:not(.form-group div.checkbox input[type=checkbox]) {
    margin-top: 10px;
}

Which aims to have a margin-top for checkboxes not inside a div.checkbox

But I want to use some default CSS for checkboxes inside a div.checkbox

However, I get this warning when I validate the CSS:

Warning: Missing a comma between function arguments

What is the proper way to do this?


Solution

  • The below won't work because the CSS :not() selector takes only simple selectors as argument and as per the W3C Specs, a simple selector is either a type selector, universal selector, attribute selector, class selector, ID selector, or pseudo-class.

    .form-group input[type=checkbox]:not(.form-group div.checkbox input[type=checkbox]) {
        margin-top: 10px;
    }
    

    The argument that is used in the above selector is a sequence or chain of simple selectors.


    The negation pseudo-class selector is in my opinion the most complex CSS selector to employ and it gets extremely messy if even one element which doesn't respect the rule is introduced somewhere in the middle. For example, a selector div:not(.checkbox) input[type=checkbox] will exclude only the second checkbox in the below structure.

    div:not(.checkbox) input[type=checkbox] {
      margin-top: 10px;
      outline: 2px solid red;
    }
    <div class='something-else'>
      <input type='checkbox' />
    </div>
    <div class='checkbox'>
      <input type='checkbox' />
    </div>
    <div class='checkbox'>
      <div class='something-else'>
        <input type='checkbox' />
      </div>
    </div>
    <div class='something-else'>
      <div class='checkbox'>
        <input type='checkbox' />
      </div>
    </div>

    You may have expected the last two checkboxes to also have been excluded because they have one div.checkbox ancestor above them but that doesn't happen because they also happen to have 1 non div.checkbox ancestor which is making the element get matched. This is why it becomes complex to use this selector.


    If your HTML structure is something like the one in the below snippet then you could use combination of direct-child selectors along with the negation pseudo-class to style only checkboxes that aren't part of a div.checkbox ancestor.

    .form-group > div:not(.checkbox) input[type=checkbox],
    .form-group > input[type=checkbox] {
      margin-top: 10px;
      outline: 2px solid red;
    }
    <form class='form-group'>
      <input type='checkbox' />
      <div class='checkbox'>
        <input type='checkbox' />
      </div>
      <div class='not-checkbox'>
        <input type='checkbox' />
      </div>
      <div class='checkbox'>
        <div class='something-else'>
          <input type='checkbox' />
        </div>
      </div>
      <div class='not-checkbox'>
        <div class='something-else'>
          <input type='checkbox' />
        </div>
      </div>  
    </form>


    Or else, you could write the rules for all checkboxes generically and then override for those which are present within the div.checkbox.

    .form-group input[type=checkbox] {
      margin-top: 10px;
      outline: 2px solid red;
    }
    .form-group div.checkbox input[type=checkbox] {
      margin-top: 0px;
      outline: none;
    }
    <form class='form-group'>
      <input type='checkbox' />
      <div class='checkbox'>
        <input type='checkbox' />
      </div>
      <div class='not-checkbox'>
        <input type='checkbox' />
      </div>
      <div class='checkbox'>
        <div class='something-else'>
          <input type='checkbox' />
        </div>
      </div>
      <div class='not-checkbox'>
        <div class='something-else'>
          <input type='checkbox' />
        </div>
      </div>  
    </form>