Re: small selector syntax addition

Ian Hickson wrote:
> 
> fantasai wrote:
> >
> > $ and :matches()
> 
> $ is this idea exactly equivalent to :subject and (...).
> 
> :matches() in this idea is exactly equivalent to :matches() in my proposal,
> after moving any selectors associated with the subject of the argument out
> to the level of the :matches() pseudo, and replacing the subject with a #.

You also wrote:
>       /* select all fleas if the document contains an antiflea element */
>       flea:matches(antiflea)

which indicates otherwise, since in the syntax I describe that would match
exactly nothing. They are not equivalent, they are merely similar.

> >     - A $ in front of a simple selector sequence indicates the subject
> >       of the selector. By default the last sequence is the subject.
> 
> This is unnecessary if you have my :matches().

This is unnecessary if you have either :matches(), but why should you
restrict the ability to change the subject of a selector to the argument
of the :matches() pseudo-class? If you have the ability to process it,
then let it be used outside--it simplifies the majority of the cases
where one would want to use such capabilities as we are discussing.

> >     Advantages:
> >
> >        3. Can be used to to make almost any selector imaginable, so it won't
> >           need to be extended with each subsequent vesion of the spec.
> 
> This isn't true. If you try to convert the selectors I gave in my last post,
> you'll see that there is at least one which your syntax cannot do.

See below.

> >        4. Parsing and processing code for the main selector can be
> >           reused to handle the :matches() argument.
> 
> I forgot to mention this as a plus point for mine.

It's not a plus point for yours.

Taking Mozilla's code as an example--
  AFAICT--and I may be wrong--Mozilla's style system matches rules to
  elements by going through the tree and sending each element, one by
  one, as an argument to nsStyleSet::ResolveStyleFor, a rule matching
  function. A set of functions take the element data and go through
  the style rules, checking the element against each rule's selector.

  Suppose we have a selector like this:  .section > div > code
  If Mozilla is checking <p class="intro">, it will return false after
  checking the 'code' part of the selector. If it's checking
  <code class="css">, it will match correctly against 'code' and then
  walk up the tree to <code class="css">'s parent and check that. If
  the parent is a <div>, it will check the <div>'s parent to see if it
  has the 'section' class.

  Now, suppose we were to implement :matches() as you describe it, and
  came upon flea:matches(antiflea). If the element in question matches
  'flea', then we have to jump to the root of the document and scan
  for antiflea. But if we had flea:matches(# antiflea), we would stay
  where we are and continue exploring flea's relations--and because
  we are inside a :matches pseudo, we are able to check elements _later_
  in the tree.

  None of this behavior applies to selectors outside the :matches()
  pseudo--not even the parsing and storing of the argument, which needs
  to handle # somehow. How can you say that the code for handling the
  main selector could be reused for handling :matches()'s argument? The
  processing has similarities, but the code for handling :matches() is
  a _superset_ of the normal selector matching code.

  Now, if I had a selector written like this:
  .section > :matches(h1,h2,h3,h4,h5,h6) + $div > code
  The <div> would be handed to the selector matching code, which would
  then walk to the <div>'s previous sibling and send that to be matched
  against :matches()'s argument, which, being a normal selector with no
  additional rules, would be processed with the same parsing and
  matching code as the main selector. It's pure recursion.
  (If <div> matched against it's prior relations, the function would then
   inspect its children for <code>.)

> >        6. A partial implementation of just $ will suffice for most needs.
> 
> I don't really understand this.

It means, if you implement $ and leave :matches() for later, you will
take care of the majority of the needed capabilities. The variety of
selectors that can be created with just $ and without :matches() may
be limited, but they are the most-used cases. 

> >        7. Reads better: .section > $div > code
> 
>     .section > div:has( > code)
> 
> I don't see that the dollar sign is any more understandable.

It's not the dollar sign. It's the fact that the whole path through
the tree is on one level.

        .section > div
                    |--:has( > code)

       vs.

        .section > div > code

Have you ever done grammar exercises where you break down and diagram a
sentence? The idea is similar to that. To express "'div' who's parent is
a '.section' and who has a child 'code'" using the $ syntax, you create
a compound "sentence" (selector). Both "clauses" are at the same level.
With your :matches() syntax, the second clause is subordinate to the
first, as you can see by the parentheses that surround it.

> >           One can see the selector as mapping unbroken path through the
> >           tree, branching only when selectors _need_ to branch off.
> >               .section > :matches(h1,h2,h3,h4,h5,h6) + $div > code
> 
> I really don't understand what you mean by that. It sounds like an
> advantage which also applies to my suggestion, though.

If you don't understand what it means, you should avoid making assuptions
about it. I actually put that point in specifically to contrast with your
suggestion.

Look at this selector:
  .section > :matches(h1,h2,h3,h4,h5,h6) + $div > code

If you visually group each sequence of simple selectors into a generic box,
you can easily see the entire pattern we are trying to match:

  [1] > [2] + {3} > [4]
               ^

The pattern only branches off through the :matches() pseudo if it's necessary
(i.e. you have two or more right-side patterns to match against) or if one,
as the author, prefers to read it that way. In your model, it always branches
off.

> You forgot the following disadvantages:
> 
>        1. Changes one of the basic concepts of CSS, that the subject of the
>           selector is the last simple selector in the chain.
> 
>        2. Can only have one description on the right hand side, unless you
>           use the :matches() form, at which point the dollar syntax is
>           redundant.
>
>        3. removes the potential use of a dollar sign from the language for
>           future extensions.
> 
>        4. Ambiguous: what does it mean if there are two $s in a selector?

It means the selector is invalid.
I think the reason you put that in for :subject was because there was no way
to handle multiple reverse relationships, and if you tried by using :subject
twice, you'd wind up with an ambiguous, undefined selector.
 
>        5. Can't describe everything.
>        /* select all fleas if the document contains an antiflea element */
>        /* can't be done */

flea antiflea,
:root:matches(antiflea, $ antiflea) flea,

No, it's not quite as simple as specifying an equivalent selector in
your syntax, but it's not that bad, and it's also a very rare case.

Also, reading flea:matches(antiflea)--just _reading_ it--in no way
seems to indicate the meaning you assign to it, whereas using the
syntax I describe, you can always read the selector literally.

> [1] this proposal allows for impossible selectors which are not possible
> using my :matches() form. For example:
>
>    $foo:matches($bar)
>
> ...can never match. These cannot be converted to the :matches() form.

And because of this, it allows you to write
  .section > :matches(h1,h2,h3,h4,h5,h6) + div
which, as you have said, cannot be converted into your :matches() form.

Note that it is not only easier to write than specifying all six
variations in full, but it is more efficient--you only match against
the div once, instead of six times.

~fantasai

Received on Saturday, 4 May 2002 17:29:06 UTC