5

Consider these classes:

.bio-target-measure {
  opacity: 1;
}
.bio-target-measure:not(.lowerThird-25.lowerThird-active):not(.lowerThird-50.lowerThird-active):not(.lowerThird-100.lowerThird-active):not(.middleThird-25.middleThird-active):not(.middleThird-50.middleThird-active):not(.middleThird-100.middleThird-active):not(.upperThird-25.upperThird-active):not(.upperThird-50.upperThird-active):not(.upperThird-100.upperThird-active):not(.bud-25.bud-active):not(.bud-50.bud-active):not(.bud-100.bud-active) {
  opacity: 0 !important;
}
<div class="mark bio-target-measure upperThird-100" title="Muestra
        Plaga: Oidio
        ID: [4]
        Tercios: [&quot;upperThird&quot;]" style="width:100.0%;height:100%;color:white;background-color:#6a6200;">Test</div>

And these jQuery call:

var measures = $('.bio-target-measure');
measures.length; // evaluates to 1.
measures.is('.bio-target-measure:not(.lowerThird-25.lowerThird-active):not(.lowerThird-50.lowerThird-active):not(.lowerThird-100.lowerThird-active):not(.middleThird-25.middleThird-active):not(.middleThird-50.middleThird-active):not(.middleThird-100.middleThird-active):not(.upperThird-25.upperThird-active):not(.upperThird-50.upperThird-active):not(.upperThird-100.upperThird-active):not(.bud-25.bud-active):not(.bud-50.bud-active):not(.bud-100.bud-active)');
// evaluates to true.

var emptyMeasures = $('.bio-target-measure:not(.lowerThird-25.lowerThird-active):not(.lowerThird-50.lowerThird-active):not(.lowerThird-100.lowerThird-active):not(.middleThird-25.middleThird-active):not(.middleThird-50.middleThird-active):not(.middleThird-100.middleThird-active):not(.upperThird-25.upperThird-active):not(.upperThird-50.upperThird-active):not(.upperThird-100.upperThird-active):not(.bud-25.bud-active):not(.bud-50.bud-active):not(.bud-100.bud-active)');
emptyMeasures.length; // evaluates to 1.

But the opacity for such element, which satisfies the selector for opacity: 0 !important; (as it was seen using jQuery), is 1. My Google Chrome (47.0.2526.106, Ubuntu 15.04, 64bits) browser uses only the first rule (the only is to clarify: rule with opacity 0 is not present-but-overriden: is totally absent in the match).

Question: is the :not rule (as I used it) a valid CSS selector? I know it works in jQuery, but I ask about CSS.

BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
Luis Masuelli
  • 12,079
  • 10
  • 49
  • 87
  • 1
    Wouldn't it be a lot easier to use a different class for the opacity, rather than excluding all those elements with `:not` – adeneo Jan 06 '16 at 16:06
  • 6
    As far as I know, CSS `:not` takes only simple selectors as input. So, the first one itself should be written as `.bio-target-measure:not(.lowerThird-25):not(.lowerThird-active)`. – Harry Jan 06 '16 at 16:06
  • The exclusion is because I use other selectors there, and add/remove classes to make the opacity. I will check now breaking the selectors – Luis Masuelli Jan 06 '16 at 16:07
  • Wait! no, I cannot break the selectors. Perhaps the element has `.lowerThird` class but, if it is not toggled (i.e. having lowerThird-active class, which I toggle with a checkbox to make a kind of filter) the effect should be the same as not having the selector – Luis Masuelli Jan 06 '16 at 16:09
  • @LuisMasuelli: In that case, I think it is better not to use `:not` selector. I can give you a sample to show how it works once the `:not` is broken (but not posting an answer because it is not a solution). – Harry Jan 06 '16 at 16:10
  • 1
    Proof of @Harry's statement: https://jsfiddle.net/av3zjd7e/1/ vs https://jsfiddle.net/av3zjd7e/ – teynon Jan 06 '16 at 16:12
  • @T.J.Crowder: Sorry, the original one should select elements which has the `bio` but not have both the other classes and the alternate I think does the same. Could you please correct me where I am going wrong?(I am referring to only the first bit by the way, not the entire selector). – Harry Jan 06 '16 at 16:13
  • 1
    Further proof of @Harry's statement: [`:not`](http://www.w3.org/TR/css3-selectors/#negation), [*simple selector*](http://www.w3.org/TR/css3-selectors/#simple-selectors), [*sequence of selectors*](http://www.w3.org/TR/css3-selectors/#simple-selectors). – T.J. Crowder Jan 06 '16 at 16:14
  • 1
    @Harry: Yeah, I think you're right. I would post that as an answer, with the links above. – T.J. Crowder Jan 06 '16 at 16:16
  • 1
    `.lowerThird-25.lowerThird-active` is a [sequence of simple selectors](http://www.w3.org/TR/css3-selectors/#selector-syntax) and [:not](http://www.w3.org/TR/css3-selectors/#negation) only accepts a [simple selector](http://www.w3.org/TR/css3-selectors/#simple-selectors) – Robert McKee Jan 06 '16 at 16:31
  • 3
    The equivalent of what you have in jQuery is actually much, much more convoluted. But yes, it boils down to it simply being invalid CSS for the reason given above. See also: [Why is my jQuery :not() selector not working in CSS?](http://stackoverflow.com/questions/10711730/why-is-my-jquery-not-selector-not-working-in-css) – BoltClock Jan 06 '16 at 17:20
  • Solved my problem using a totally different approach. How should I handle the question? – Luis Masuelli Jan 06 '16 at 17:57
  • You can answer your own question. – BoltClock Jan 07 '16 at 03:42
  • @T.J.Crowder: Sorry mate, you were correct. The selector I gave above (chained) was indeed wrong. `:not(.lowerThird-25):not(.lowerThird-active)` fails to select an element even if only one of them is present. [Here](https://jsfiddle.net/yga3sd1x/) is a demo of the correct and wrong ones based on BoltClock's answer in the linked thread. – Harry Jan 07 '16 at 08:42
  • 1
    @Harry: I *thought* so, thanks. :-) – T.J. Crowder Jan 07 '16 at 08:45
  • @Harry I retwisted the problem to avoid using such selectors but different (complementary - avoiding :not) ones. Anyway, in my Chrome browser, the link you gave me does not show the expected colors (the first two show as red when they should be green by what their text tells) – Luis Masuelli Jan 07 '16 at 18:02
  • @LuisMasuelli: That is actually the point. The first set of selectors are wrong and that is why they don't change the text color. If you refer my original comment that is the selector which I had given. The second set of selectors which change the background to beige are the correct ones. They style all elements which doesn't have both the classes together. – Harry Jan 07 '16 at 18:08

2 Answers2

4

Following from @Harry's comment, you cannot have combined selectors in your :not(). (Evidence provided by @TJCrowder: :not, simple selector, sequence of selectors)

In a case like this, you will need to rework your logic:

.bio-target-measure.lowerThird-25:not(.lowerThird-active),
.bio-target-measure.lowerThird-50:not(.lowerThird-active),
...

This can be made a lot easier using LESS or a similar higher-level version of CSS:

.bio-target-measure {
    &.lowerThird-25, &.lowerThird-50, &.lowerThird-100 {
        &:not(.lowerThird-active) {
            opacity: 0 !important;
        }
    }
    /* define similar blocks for middleThird and upperThird */
}

The above will compile into the complicated selector suggested in the first code block, while being much easier to read.

Niet the Dark Absol
  • 320,036
  • 81
  • 464
  • 592
  • Although the second part (the one with the example starting with "This can be made...") is not appropriate to my problem, the first part is the one that answers the question. Should I accept it? Or an edit could be made before? – Luis Masuelli Jan 06 '16 at 17:58
  • Sorry again mate. My previous comment was wrong. I had misunderstood the way chaining and splitting works. Your selector is more closer to the requirement than the one I had given in comments. – Harry Jan 07 '16 at 08:24
0

In fact, what @NietTheDarkAbsol answered is -half- the expected answer: My selector was not valid in CSS (yes, in jQuery).

However, rewording the logic also needs to preserve the classes relationship. This means:

A .bio-target-measure not satisfying the following 4 conditions simultaneously, must have an opacity of 0:

  • .lowerThird-(25|50|100).lowerThird-active
  • .middleThird-(25|50|100).middleThird-active
  • .upperThird-(25|50|100).upperThird-active
  • .bud-(25|50|100).bud-active

The selector in his answer produces a 0 when at least one of the corresponding -active filters is not set. Since multiple -active filters could be available for each mark, the solution had to be reworded in a by-default-negative way (i.e. opacity is 0 by default, and will not be 0 when having additional classes). The sass script is like this:

.bio-target-measure {
  @each $lowerThird in 0, 25, 50, 100 {
    @each $middleThird in 0, 25, 50, 100 {
      @each $upperThird in 0, 25, 50, 100 {
        @each $bud in 0, 25, 50, 100 {
          $lowerThirdClass: '.lowerThird-#{$lowerThird}.lowerThird-active';
          $middleThirdClass: '.middleThird-#{$middleThird}.middleThird-active';
          $upperThirdClass: '.upperThird-#{$upperThird}.upperThird-active';
          $budClass: '.bud-#{$bud}.bud-active';

          @if $lowerThird == 0 { $lowerThirdClass: ''; }
          @if $middleThird == 0 { $middleThirdClass: ''; }
          @if $upperThird == 0 { $upperThirdClass: ''; }
          @if $bud == 0 { $budClass: ''; }

          $sum: $lowerThird + $middleThird + $upperThird + $bud;
          @if $sum > 50 {
            $sum: 100;
          }

          &#{$lowerThirdClass}#{$middleThirdClass}#{$upperThirdClass}#{$budClass} {
            opacity: $sum / 100;
          }
        }
      }
    }
  }
}
Luis Masuelli
  • 12,079
  • 10
  • 49
  • 87