- From: Allan Sandfeld Jensen <kde@carewolf.com>
- Date: Mon, 13 Jun 2011 13:49:04 +0200
- To: www-style@w3.org
Hello www-style I would like to make a few comments on the CSS4 selectors draft. The issues concern "limited ancestor combinator", and :not selector with combinators. The first problem is the well-known is the issue that using combinators within :not() selector is not intuitive, while easy to implement, the results are not always what you expect. The underlying confusion comes down to the problem of inverting the ancestor combinator. It is easiest to describe by arguing looking at what happens in bottom-up matching. 'A *' means that an element matches if one of the ancestors matches 'A', or in other words, if an ancestor matches 'A' the expression matches, if if does not match 'A', the expression continues to match the rest of the ancestors. Inverting the entire combinator inverts the expression to look for the first failure. 'A' ':not(A)' ----------------------------------------- 'A *' match continue ':not(A) *' continue match ':not(A *)' fail continue ':not(:not(A) *)' continue fail It is a bit counter-intuitive, but I think it is quite useful. I would give it another name though such as :never. I would add another restriction to it though, so it only fails until another expression matches, combining a negative failure condition to guarantee while looking for the possive condition normally specified before the ancestor combinator. This turns out to fits right into the limited ancestor combinator problem. Let us look at some examples: 1. Select only first level of <item> under a <list> 2. Select only elements that is not embedded deeper in another <list> 3. Select only elements that is not embedded under another element with attribute 'LANG'. The way I propose to implement all of these is using a never-selector. I am not sure it is best expressed using pseudo-class syntax, but for this example I will use that. The :never(X) selector fails the selector if the selector-argument is ever true in the scope that is matched in. In normal use it is no different from a :not(X) selector, but in an indirect combinator such as ancestor or indirect- sibling it changes the behavior of a failure to mean complete fail, instead of 'continue matching'. 1. list item:never(item) The form x:never(x) might look a bit weird, but could for clarity be written as :first(x), it does the same though. It stops the ancestor combinator from matching items embedded within items. 2. list *:never(list). This creates a scope of limited ancestor selectors. 3. [lang|=en] *:never([lang]) This implements the attribute-matching part of :lang(en) selector using the new syntax. The clever part here is that the matching part within the :never selector does not need to be the same as the selector after the ancestor combinator, in this case making it possible to create a scope based on a broader matche [lang], than the ancestor match [lang|=en]. One problem might be the syntax though. Another option is to put the requirement in beside the combinator. Also the complement requirement :never(:not()) can be useful at times. I would call it :always. For instance 'svg#thisimage :always(svg|*)' could ensure it only matches svg descendants, but not those embedded in embedded foreign objects. I hope you find my comments useful. I look forward to seeing the final results of the CSS 4 selector in the future. Best regards `Allan Sandfeld
Received on Monday, 13 June 2011 11:49:45 UTC