2

I have this situation

<div class="hidden">
  <input name="bar-foo" value="test"> 
</div>
<div class="hidden">
  <input name="bar-foo-baz" value="test2">
</div>
<div class="nothidden">
  <input name="bar-foo" value="test3"> <!-- should be selected -->
</div>
<div class="nothidden">
  <input name="foo-bar-baz" value="test4"> <!-- should be selected -->
</div>

I need to match inputs containing word foo and bar, not contained in a div which class is 'hidden'.

input[name*="foo"][name*="bar"] 

matches all the four inputs.

:not(.hidden) input[name*="foo"][name*="bar"]

in my opinion, should match inputs not contained in something with class '.hidden', but it doesn't. How do I achieve this result?

Here is it a jsfiddle https://jsfiddle.net/8dLbz5ws/1/

Sasha Grievus
  • 2,566
  • 5
  • 31
  • 58
  • 2
    `div:not(.hidden)` rather than `:not(.hidden)` perhaps? – DBS Nov 15 '17 at 16:47
  • Specifying an element does work (verified: https://jsfiddle.net/8dLbz5ws/3/) But why this is the case, I don't know. According to MDN examples, your use-case should apply: https://developer.mozilla.org/en-US/docs/Web/CSS/%3Anot – UncaughtTypeError Nov 15 '17 at 16:51
  • @UncaughtTypeError Since it's not using a direct descendant selector, and things like the `body` don't have the `hidden` class, the style will always be applied. – DBS Nov 15 '17 at 16:53
  • Yes, I realised this looking at @arbuthnott answer (one of those "obvious now that I see it" things) – UncaughtTypeError Nov 15 '17 at 16:54

4 Answers4

7

Your second selector :not(.hidden) input[name*="foo"][name*="bar"] matches all the inputs because they are all contained in some element that doesn't have the hidden class (for example the body or another parent div).

You can fix the problem by being more specific:

:not(.hidden) > input[name*="foo"][name*="bar"]

This will filter out those with .hidden direct parents.


EDIT

Some commenters would like to know how to select all the inputs in question that are not contained in any .hidden element (not necessarily a direct parent). This is a tougher problem. The following:

input[name*="foo"][name*="bar"]:not(.hidden input)

does not seem to work, I think because :not only permits relatively simple selectors inside. The only way I can think of is to update all the chosen inputs and then un-update them when within any .hidden elements:

input[name*="foo"][name*="bar"] { color: red; }
.hidden input[name*="foo"][name*="bar"] { color: black; }

This will only work if the default settings (ie color: black) is uniform I'm afraid.

arbuthnott
  • 3,819
  • 2
  • 8
  • 21
  • 1
    Yes, that makes a lot of sense - well spotted. – UncaughtTypeError Nov 15 '17 at 16:52
  • how is for `

    ` ?
    – Ehsan Nov 15 '17 at 16:59
  • i think your answer is wrong because selects `input` inside `p`. – Ehsan Nov 15 '17 at 16:59
  • @Ehsan I've been wrong before :) But I don't see the problem. Can you explain? – arbuthnott Nov 15 '17 at 17:02
  • @Ehsan In your example, `p` does not have `.hidden` - so it correctly selects the input inside it. However if `p` was nested inside a `div.hidden` then it would fail - is that what you mean? – sol Nov 15 '17 at 17:04
  • @ovokuro , but it is not a `div`.problem is right here! – Ehsan Nov 15 '17 at 17:07
  • 1
    @Ehsan - Oh I see what you mean. I guess this answer works for the OP's question, but you are right it might need to be more specific – sol Nov 15 '17 at 17:08
  • And if there's a number of other div in the middle? Like – Sasha Grievus Nov 15 '17 at 17:14
  • 1
    @Ehsan I see what you mean. It's a different problem to select anything not inside *any* `.hidden` element. My answer just points out the general cause of error, and how to fix it for this specific case. – arbuthnott Nov 15 '17 at 17:15
  • Tried the edit, but seem not to work in the case there are other elements in the middle (I agree it should) – Sasha Grievus Nov 15 '17 at 17:25
  • 1
    @SashaGrievus, I can see that too in the fiddle. It looks like `:not` only permits fairly simple selectors in the argument. I'll try to update to something else that will work. – arbuthnott Nov 15 '17 at 17:38
  • "The following does not seem to work, I think because `:not` only permits relatively simple selectors inside." It [doesn't work in CSS](https://stackoverflow.com/a/10711731), but it [works in jQuery](https://jsfiddle.net/u3e9a83o/1/), which [doesn't have that restriction](https://api.jquery.com/not-selector/): "All selectors are accepted inside `:not()`, for example: `:not(div a)` and `:not(div,a)`." – chocolateboy Apr 11 '18 at 21:59
1

This worked for me.

https://jsfiddle.net/1dd2a3sw/

div:not(.hidden) input[name*="foo"][name*="bar"] {
  color:red;
}
bassxzero
  • 4,838
  • 22
  • 34
1

change like this:

div:not(.hidden) input[name*="foo"][name*="bar"] {
    background-color: yellow;
}

div:not(.hidden) input[name*="foo"][name*="bar"] {
 background-color: yellow;
}
<div class="hidden">
  <input name="bar-foo" value="test"> 
</div>
<div class="hidden">
  <input name="bar-foo-baz" value="test2">
</div>
<div class="nothidden">
  <input name="bar-foo" value="test3"> <!-- should be selected -->
</div>
<div class="nothidden">
  <input name="foo-bar-baz" value="test4"> <!-- should be selected -->
</div>
Ehsan
  • 12,655
  • 3
  • 25
  • 44
1

Try targetting only the direct children of your classes that are not hidden, like this:

:not(.hidden) > input[name*="foo"][name*="bar"] { color:blue; }
Sorix
  • 850
  • 5
  • 18