3

Given this selector:

body[class*="page-node-add-"][class~="page-node-edit"] {background:red;}

It will match a body which has a class that contains a substring of page-node-add- AND a class which is exactly page-node-edit

I would like to say match the first OR the second (but not both). Is it possible?

The problem with using a comma:

If I have a long selector like:

body[class*="page-node-add-"] form.node-form > .field-type-field-collection > table > thead tr th,
body[class~="page-node-edit"] form.node-form > .field-type-field-collection > table > thead tr th
{...}

That is a pain I would have thought CSS3 would remedy that, I was imagining something like:

body([class*="page-node-add-"]):or([class~="page-node-edit"]) {background:red;}

Thanks

BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
Dominic
  • 62,658
  • 20
  • 139
  • 163
  • Seriously, you have to work on your style writing CSS, your selectors look (and most likely perform) horrible. – Christoph May 25 '12 at 11:29
  • Thanks but I know how to write css very well and this is not how I would normally do it. I have a task to go into 1000s of lines of CMS produced markup in the admin area (so browser compatibility not an issue and try and colour code and collapse element etc with css and js so that it makes sense to the average website editor – Dominic May 25 '12 at 11:49

3 Answers3

4

You'll need to split them up using a comma:

body[class*="page-node-add-"], body[class~="page-node-edit"] {background:red;}

The problem with using a comma:

... is that you can't do it any other way than with a comma. Perhaps it could have been remedied with Selectors 3, but unfortunately the spec says otherwise. That is only going to be remedied by Selectors 4, either because it wasn't proposed until recently, or it was proposed but didn't make the cut for level 3.

In level 4 of Selectors you will be able to do something like this:

body:matches([class*="page-node-add-"], [class~="page-node-edit"]) form.node-form > .field-type-field-collection > table > thead tr th
{...}

Currently, this is being implemented under its originally-proposed name, :any(), with the prefixes :-moz-any() and :-webkit-any(). But using :any() in public-facing CSS is pointless given that

  1. only Gecko and WebKit support it; and

  2. you have to duplicate your rulesets because of the way prefixed selectors are handled, which not only defeats the intended purpose of the :matches() selector, but makes things even worse:

    body:-moz-any([class*="page-node-add-"], [class~="page-node-edit"]) form.node-form > .field-type-field-collection > table > thead tr th
    {...}
    body:-webkit-any([class*="page-node-add-"], [class~="page-node-edit"]) form.node-form > .field-type-field-collection > table > thead tr th
    {...}
    

In other words, until implementations update themselves to the standardized :matches(), there is no other viable solution (save from using a preprocessor to generate the repeated selectors for you).

Community
  • 1
  • 1
BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
  • Similar answer (whch I like a tad more as it links to another prior answer to this) is http://stackoverflow.com/a/10753421/2255628 (also on this page). – Destiny Architect Jun 18 '15 at 01:17
  • @Destiny Architect: I actually prefer this answer to the prior one as this one highlights the counter-productiveness of using the prefixes in production. But I should probably mark the questions as duplicates anyway. It's just a matter of which one should be the dupe target. – BoltClock Jun 18 '15 at 05:52
1

I found the answer here:

CSS Shorthand to identify multiple classes

Mozilla and webkit has a -moz-any or -webkit-any, though in the CSS4 spec there is a :matches. Suprised this wasn't thought of in CSS3 as it would greatly reduce the amount of repetative code without having to use SASS or LESS or whatever.

Community
  • 1
  • 1
Dominic
  • 62,658
  • 20
  • 139
  • 163
  • Yeah, but because of the prefixes you have to duplicate the rules. Applying that other answer of mine to what you have, you can see that it doesn't really help matters... – BoltClock May 25 '12 at 11:17
  • Similar answer is http://stackoverflow.com/a/10753216/2255628 (also on this page). ‘matches’ good description at https://css-tricks.com/almanac/selectors/m/matches/ but currently not in http://caniuse.com/#search=matches as https://dom.spec.whatwg.org/#dom-element-matchesselectors is not the same. – Destiny Architect Jun 18 '15 at 01:14
1

So you really want XOR when I read your question. You can achive this by using the :not selector and say "class one and not the other" and the other way around.

div.one:not(.two), div.two:not(.one) {
    background:red;
}

Here is a fiddle: http://jsfiddle.net/XfgxK/3/

Fabian Barney
  • 14,219
  • 5
  • 40
  • 60
  • That's exactly what he wants as far as I understood the question right. – Fabian Barney May 25 '12 at 11:30
  • Once you replace those classes with the given attributes or the full complex selectors, this gets crazy long. Again, there's no viable workaround for it yet. – BoltClock May 25 '12 at 11:30
  • @BoltClock Nope, OP is asking for xor. – Christoph May 25 '12 at 11:30
  • Well, this is pretty confusing. The OP found another answer of mine which says exactly the same thing and he calls it "the answer", but after a second read it does seem like he's asking for XOR, not OR. – BoltClock May 25 '12 at 11:33
  • Also, unless you have other classes to filter by, you don't necessarily have to say `div.one:not(.two)`, you can simply say `div:not(.two)`. See http://jsfiddle.net/BoltClock/XfgxK/4/ and http://stackoverflow.com/questions/10711730/whats-the-difference-in-the-not-selector-between-jquery-and-css/10711731#10711731 – BoltClock May 25 '12 at 11:37
  • 1
    Yep, but you've to be aware that this is another scenario since you're matching former unrelated div's now. http://jsfiddle.net/TyYJ5/1/ Which is not the case when using the former code: http://jsfiddle.net/XfgxK/5/ – Fabian Barney May 25 '12 at 11:40