2

I would like to select all input that is not a child of a parent having the class no-material

I used this selector, main *:not(.no-material) input, which, to me, should work and select the last 4 inputs, but it doesn't.

Is this not possible, or what am I missing here?

Note, I know this can be done by first select all, and then deselect some, though that is exactly what I want to avoid.

Stack snippet

main *:not(.no-material) input {
  border: 1px solid red;
}
<main>

  <div class="no-material">
    <input name="no-1">
  </div>

  <div>
    <label class="no-material">
      <input name="no-2">
    </label>
  </div>

  <div>
    <label class="no-material">
      <span>
        <input name="no-3">
      </span>
    </label>
  </div>

  <div>
    <label>
      <span class="no-material">
        <input name="no-4">
      </span>
    </label>
  </div>

  <div>
    <input name="no-1">
  </div>

  <div>
    <label>
      <input name="no-2">
    </label>
  </div>

  <div>
    <label>
      <span>
        <input name="no-3">
      </span>
    </label>
  </div>

  <div>
    <label>
      <span>
        <input name="no-4">
      </span>
    </label>
  </div>

</main>

As a side note, when done like this it works just fine and select the first 4 input's

main *.no-material input {
  border: 1px solid blue;
}

Stack snippet

main *.no-material input {
  border: 1px solid blue;
}
<main>

  <div class="no-material">
    <input name="no-1">
  </div>

  <div>
    <label class="no-material">
      <input name="no-2">
    </label>
  </div>

  <div>
    <label class="no-material">
      <span>
        <input name="no-3">
      </span>
    </label>
  </div>

  <div>
    <label>
      <span class="no-material">
        <input name="no-4">
      </span>
    </label>
  </div>

  <div>
    <input name="no-1">
  </div>

  <div>
    <label>
      <input name="no-2">
    </label>
  </div>

  <div>
    <label>
      <span>
        <input name="no-3">
      </span>
    </label>
  </div>

  <div>
    <label>
      <span>
        <input name="no-4">
      </span>
    </label>
  </div>

</main>

I also want to give credit to this post from where I got the main code sample, though they seek a solution for Javascript and querySelectorAll(), and I hoped for a CSS rule (or two :)

Asons
  • 84,923
  • 12
  • 110
  • 165

3 Answers3

3

The problem here is that your code satisfies too many scenarios.

For example, the following will satisfy your rule.

<div>
  <label class="no-material">
    <span>
      <input name="no-3">
    </span>
  </label>
</div>

This is because the span is an element without that class that precedes an input.

What you could do is apply the rule you want to all inputs and then override the ones that have that class to be back to the original style.

For example:

main input {
  border: 1px solid blue;
}
main .no-material input {
  border: 1px solid black;
}
Jennifer Goncalves
  • 1,442
  • 1
  • 12
  • 29
  • Of course it does....thank you :) ... _sometimes one can't see the forest because of all the tree's..._ – Asons Jun 12 '17 at 10:51
1

You could even try as below, as placement of class .no-material is in different tags, so you could target each tag and search for class in it and style,

main * input{
 border:1px solid red;
}
div[class*="no-material"] input{
  border: 1px solid #ccc;
}
label[class*="no-material"] input{
  border: 1px solid #ccc;
}
span[class*="no-material"] input{
  border: 1px solid #ccc;
}
<main>

 <div class="no-material">
    <input name="no-1">
  </div>

  <div>
    <label class="no-material">
      <input name="no-2">
    </label>
  </div>

  <div>
    <label class="no-material">
      <span>
        <input name="no-3">
      </span>
    </label>
  </div>

  <div>
    <label>
      <span class="no-material">
        <input name="no-4">
      </span>
    </label>
  </div>

  <div>
    <input name="no-1">
  </div>

  <div>
    <label>
      <input name="no-2">
    </label>
  </div>

  <div>
    <label>
      <span>
        <input name="no-3">
      </span>
    </label>
  </div>

  <div>
    <label>
      <span>
        <input name="no-4">
      </span>
    </label>
  </div>

</main>
frnt
  • 8,455
  • 2
  • 22
  • 25
  • Thanks for your answer. Yes, though I want to avoid to first set a property on all and then remove it on some. And to do that I can simply combine the 2 rules I have in the question, and they will do the same as this one, but simpler, still, upvoted :) – Asons Jun 12 '17 at 11:29
  • Welcome @LGSon :-). Okay I even tried that using :not() selector, but for some reason didn't work or it might have solved by much lesser styling codes and simpler too. – frnt Jun 12 '17 at 11:35
1

I would like to select all input that is not a child of a parent having the class no-material.

The solution is hinted in that request: ...is not a child ...

Instead of a descendant combinator:

main *:not(.no-material) input

Use a child combinator:

main *:not(.no-material) > input

main *:not(.no-material) > input {
  border: 1px solid red;
}
<main>

  <div class="no-material">
    <input name="no-1">
  </div>

  <div>
    <label class="no-material">
      <input name="no-2">
    </label>
  </div>

  <div>
    <label class="no-material">
      <span>
        <input name="no-3">
      </span>
    </label>
  </div>

  <div>
    <label>
      <span class="no-material">
        <input name="no-4">
      </span>
    </label>
  </div>

  <div>
    <input name="no-1">
  </div>

  <div>
    <label>
      <input name="no-2">
    </label>
  </div>

  <div>
    <label>
      <span>
        <input name="no-3">
      </span>
    </label>
  </div>

  <div>
    <label>
      <span>
        <input name="no-4">
      </span>
    </label>
  </div>

</main>

The original code matches all descendants, not just the children. So it fails to work as expected.

Here is a more complete explanation: https://stackoverflow.com/a/42353253/3597276

Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
  • Thanks for answering. Tried that, and it doesn't fully work for the reason [Jennifer](https://stackoverflow.com/a/44497536/2827823) gave. If you check your snippet you'll see that the 3:rd item with the class gets selected, which it shouldn't, still, upvoted :) – Asons Jun 12 '17 at 12:28
  • Yeah, but that's not a child. That's a descendant. Your request was: *I would like to select all `input` that is not a* ***child*** *of a parent having the class `no-material`*. – Michael Benjamin Jun 12 '17 at 12:30