W3C home > Mailing lists > Public > www-style@w3.org > April 2013

Re: [css-selectors] Proposal: Logical Combinators / Sets

From: Simon Sapin <simon.sapin@exyr.org>
Date: Sat, 06 Apr 2013 12:27:00 +0200
Message-ID: <515FF874.1000108@exyr.org>
To: Brian Kardell <bkardell@gmail.com>
CC: "www-style@w3.org" <www-style@w3.org>
Le 06/04/2013 01:05, Brian Kardell a écrit :
> Let me make a couple of points (some of them restated from post and article):
>    -  These are only significant (useful/necessary) if all of them can
> take complex selectors
>     - :matches and :not are already in there and they probably map to
> two of these, but neither takes complex selectors yet.

I agree that complex selectors and :not() and :matches() would be great 
to have. Apparently so does Tab, who edited Selectors 4 just two days 
ago to add that.

Right now the feature is only in a "complete" profile:
http://dev.w3.org/csswg/selectors4/#profiles

If implementers find a way to make it fast enough, I suppose there would 
be no need for profiles anymore.


>   -  Lots of things are currently solved today by modifying the markup
> or DOM via for presentation purposes and that is less than ideal, it's
> not the vision.  To reach that vision, we need nice semantic markup
> (global and local semantics) and rich selector capabilities.

I agree on the general idea, but it says nothing about what specific 
features are needed to get there.


>     - I think pseudos that use well-established mathematical or CS
> terms is intuitive.

This is debatable, but in any case I don’t think this is a strong enough 
reason to add redundant syntax for existing features.


> As a rule, the examples I've seen are too simplistic to add much
> benefit anyway..  Here is the example for where the current
> implementation of :matches (simple selectors) benefits used in David
> Barron's original blog post[1]:
>
>
>      /* 3 deep (or more) unordered lists use a square */
>      ol ol ul,     ol ul ul,     ol menu ul,     ol dir ul,
>      ol ol menu,   ol ul menu,   ol menu menu,   ol dir menu,
>      ol ol dir,    ol ul dir,    ol menu dir,    ol dir dir,
>      ul ol ul,     ul ul ul,     ul menu ul,     ul dir ul,
>      ul ol menu,   ul ul menu,   ul menu menu,   ul dir menu,
>      ul ol dir,    ul ul dir,    ul menu dir,    ul dir dir,
>      menu ol ul,   menu ul ul,   menu menu ul,   menu dir ul,
>      menu ol menu, menu ul menu, menu menu menu, menu dir menu,
>      menu ol dir,  menu ul dir,  menu menu dir,  menu dir dir,
>      dir ol ul,    dir ul ul,    dir menu ul,    dir dir ul,
>      dir ol menu,  dir ul menu,  dir menu menu,  dir dir menu,
>      dir ol dir,   dir ul dir,   dir menu dir,   dir dir dir {
>          list-style-type: square;
>      }
>
> The current :matches is just sugar, but that's not a bad thing - it
> makes rules considerably more readable and therefore maintainable...
> It is much easier to reason about something like:
>
>      :-moz-any(ol, ul, menu, dir) :-moz-any(ol, ul, menu, dir)
> :-moz-any(ul, menu, dir) {
>          list-style-type: square;
>      }
>
> Than it is the expanded form  (above).  So let's not immediately think
> "sugar is unnecessary" or bad - in fact, there is a benefit to the
> above in that in theory all you need to do is write the
> unwinding/expansion and then the underlying support is already in the
> browser, and there is a benefit that it is easier to write software to
> reason about that as well - you could potentially speed things up by
> knowing where the logical forks are.

Yes, this is why I said that :oneof() could be useful: when you need it, 
it makes selectors significantly shorter, easier to write, and easier to 
read. Maybe easier to implement fast, too.

The question is: when do you really need it? Are there use cases for XOR 
in selectors, enough to justify the cost of a new feature?


:allof() however does not make anything significantly better.
:allof(a, b, c) can be written :matches(a):matches(b):matches(c), which 
is longer but grows linearly. There is no combinatorial explosion, 
unlike the :matches(ol, ul) :matches(ol, ul) example.

As to :anyof()/:noneof(), they are really the same as :matches()/:not(), 
so this is only about naming.


> Given support for complex selectors, however, things change even in
> the overly simplistic examples.  You gave:
>
>      .foo .bar:matches(ol li)

This might be easier to read as :matches(.foo .bar):matches(ol li)


[snip]
> As I mentioned
> above, we need something reasonably rich to show the value, so let's
> use my examples...  I called it "anyof", but it could be:
>
>      /* Style the cars that are foreign and used or domestic, new and
> effiecient. */
>      .cars div:matches(.foreign .used, .domestic .new .efficient) p {
>          color: blue;
>       }
>
> When I read this, I am personally unsure whether the things inside are
> AND'ed or OR'ed since the break is inside parens.  Ok, that is
> probably teachable...

Exactly, this is teachable. A comma in selectors is always OR. Unless we 
add a feature where it’s not, but I think we should not.


> Flip to my :allof - you could desugar that to:
>
>       cars div:matches(.new .quality):matches(domestic .performance) p {
>          color: red;
>       }
>
> And my noneof example:
>
>       /* Style the efficient cars that are neither domestic and used
> nor foreign and new. */
>      .efficient:not(.domestic .used):not(foreign .new) p {
>          color: green;
>       }
>
> What would (or would we always disallow) this do?  Would it be true if
> one was not, or would they all have to be not?  The later seems in
> keeping with what :matches is proposed to do so I'd suggest that:
>
>       /* Style the efficient cars that are neither domestic and used
> nor foreign and new. */
>      .efficient:not(.domestic .used, foreign .new) p {
>          color: green;
>       }

If you want "domestic and used" as in the comment, remove the whitespace 
(descendant combinator) between the two class selectors.

:not(.domestic.used):not(.foreign.new) is the same as
:not(.domestic.used, .foreign.new), just like Morgan’s law in boolean 
algebra says that not(A) and not(B) is the same as not(A or B).


> As far as I can tell, there is currently no way to write my "oneof"
> example -  I have  wanted it in the past myself.

It is possible: boolean (A XOR B) is ((A and not(B)) or (B and not(A)). 
Granted, it is much longer to write, and redundant.

But again: is XOR really needed? Can you give use cases?


> Maybe that is enough and maybe it is intuitive enough - I find it
> easier to reason about using set or predicate sorts of language which
> don't leave the "what does that mean" sorts of questions I mentioned
> above, but maybe that isn't a good enough case.

Then this is not about missing features, it is about teaching. What I’m 
hearing here is that we need good documentation that explains selectors 
in terms of boolean algebra or set theory.

The comma is OR/union, juxtaposition is AND/intersection, etc.


> All of this is a bit of a chicken and egg problem we have here (I'm
> glad someone in Lea's border-corners thread mentioned this):  People
> work around these limitations today - but they do so by modifying the
> DOM itself by either changing markup or through JavaScript - or they
> just use an image or something and lose the data - because they have
> no other choice - and given new powers, smart people will do new
> things.

Again, I agree on the general principle. I’m arguing but these specific 
feature requests.

-- 
Simon Sapin
Received on Saturday, 6 April 2013 10:27:25 UTC

This archive was generated by hypermail 2.3.1 : Monday, 2 May 2016 14:39:10 UTC