- From: Lachlan Hunt <lhunt07@netscape.net>
- Date: Sun, 07 Dec 2003 22:58:45 +1100
- To: www-style@w3.org
Hi, While experimenting with XHTML2, I have discovered some limitations with CSS. Based on these I have come up with a few proposals for CSS3. Sorry for making this long, but I have put a lot of effort and thought into this and tried to be as clear as possible. -- XHTML 2 Example -- Throughout this post, all my CSS examples will apply to this XHTML 2 fragment: <body> <section> <h>Heading 1</h> <div> <section> <h>Heading 1.1</h> </section> </div> <section> <h>Heading 1.2</h> <section> <h>Heading 1.2.1</h> </section> </section> </section> </body> -- Limitations -- 1. There is no easy way to select a specific section level because other block elements may appear between, with just one selector. eg. In the above example, with the <div> appearing before the first second level section (1.1), but not the second (1.2), the following cannot be used: body > section section > h { /* Selects both 2nd and 3rd levels (1.1, 1.2 and 1.2.1) */ color: green; } body > section > section > h { /* Does not select Heading 1.1 Only selects Heading 1.2 */ color: red; } 2. There is no shorthand method for selecting the nth descendant level of an element. eg. shorthand for selecting the 6th level section: body > section > section > section > section > section > section which also has the problems of the above limitation. -- Proposals to Solve these Limitations -- I have come up with two potential solutions. One using a combinator and the other using pseudo classes. I think the pseudo classes are more flexible, but the pseudo classes may be easier to understand, after understanding the concept of the combinator. -- Combinator -- Just as there are direct adjacent '+' and indirect adjacent '~' sibling combinators, I propose there be an indirect descendant combinator to pair with the child combinator '>' (since a child element is a simply a direct descendant) This would differ from the normal descendant selector (white space) in that it would only select the first matching descendant element regardless of any nested elements between such as the <div> in the above example. I'll use the symbol '^' to represent this because of it's similarity in shape to the child descendant selector '>', and also because it kind of represents a simple tree structure like xml (though with only 2 branches), but the symbol doesn't really matter. body > section ^ section { /* This selects Headings 1.1 and 1.2, but NOT Heading 1.2.1 */ } * Advantages Very simple and effective * Disadvantages Not very flexible. For example: can't select the last, or last of type, descendants in the tree. For example, selecting both sections 1.1 and 1.2.1. -- Pseudo Classes -- Just like there are :nth-child(n) and :nth-of-type(n) pseudo classes that apply only to children of the same parent, I think it would be useful if there were :nth-descendant pseudo classes as well that apply to descendants of the same ancestor, following the document tree. There are eight pseudo classes that I'll introduce, which I have derived from the :nth-, :nth-last-, :first- and :last-child() and -of-type() pseudo classes, and applied to descendants. I believe these pseudo classes can only be effective when used with the descendant selector (white space). My use of the term 'descendant level' means the number of descendant elements along any given path. If an equivalent term has already been used in CSS, then it should be used instead. eg. <x> <y/> <z/> </x> The <x> element only has one descendant level, even though there are two children <x> <y> <z/> </y> <z/> </x> This <x> element now has two descendant levels. - Descendant Pseudo Classes - * :nth-descendant(an+b) The :nth-descendant(an+b) pseudo-class notation represents an element that has exactly an+b-1 ancestors in the document tree, which are also descendants of any specified ancestors, for a given zero or positive integer value of n. If no ancestors are specified, then the root element is used. * :nth-last-descendant(an+b) The :nth-last-descendant(an+b) pseudo-class notation represents an element that has exactly an+b-1 descendant levels in the document tree, for a given zero or positive integer value of n. * :first-descendant Same as :nth-descendant(1), but with a lower specificity. * :last-descendant Same as :nth-last-descendant(1), but with a lower specificity. - Descendant of Type Pseudo Classes - * :nth-descendant-of-type(an+b) The :nth-descendant-of-type(an+b) pseudo-class notation represents an element that has exactly an+b-1 ancestors with the same element name in the document tree, which are also descendants of any specified ancestors, for a given zero or positive integer value of n. If no ancestors are specified, then the root element is used. * :nth-last-descendant-of-type(an+b) The :nth-last-descendant-of-type(an+b) pseudo-class notation represents an element that has exactly an+b-1 descendant levels with the same element name in the document tree, for a given zero or positive integer value of n. * :first-descendant-of-type Same as :nth-descendant-of-type(1), but with a lower specificity. * :last-descendant-of-type Same as :nth-last-descendant-of-type(1), but with a lower specificity. For the :nth-descendant(an+b) pseudo classes, when an+b = 1, it may appear to be equivalent to the :first-child or nth-child(an+b) pseudo classes, however, these classes will only select one matching child, whereas nth-descendant(1) will select all matching children. I nearly made this mistake myself, so I want to make sure everything is as clear as possible. I have tried to be as accurate as possible with my definitions, but I still may have made some minor mistakes. If in doubt, the following examples illustrate their intended meaning. -- Examples -- These examples will show general use cases for the elements, and state whether or not it is a final solution to the above stated limitation. Even though one example is not a solution to this specific problem, does not mean it won't be for others. 1. body section:nth-decendant(0n+2) > h This selects the <h> elements within all <section> elements that have exactly 1 ancestor in the document tree, which are descendants of the body element. * Selects: Heading 1.2 (body > section > section > h) * Does Not Select: Heading 1.1 because the extra div is another ancestor (body > section > div > section > h) 2. body section:nth-last-decendant(0n+2) > h This selects the <h> elements within all <section> elements that have exactly 1 descendant level in the document tree, * Selects: Heading 1.1 because it's section's only descendant is the <h> element (body > section > div > section > h) Heading 1.2.1 for the same reason (body > section > section > section > h) 3. body section:nth-decendant-of-type(0n+2) > h This selects the <h> elements within all <section> elements that have exactly 1 ancestor, of type section, in the document tree, which are descendants of the body element. * Selects: Heading 1.1 because there is only one ancestor of type section before it. The div ancestor is ignored. (body > section > div > section > h) Heading 1.2 (body > section > section > h) 4. body section:nth-last-decendant-of-type(0n+2) This selects the <h> elements within all <section> elements that have exactly 1 descendant level, of type section, in the document tree element. * Selects: Heading 1.2 because it has 1 descendant of type section for Heading 1.2.1. (body > section > section > h) The :first- and :last- versions don't need examples since they are just shorthand for when an+b = 1. -- One Final Pseudo Class -- This is directly related to limitation 2 from the beginning. A shorthand method for specifying repeating selectors like: body > section > section > section > section > section > section > h could be something like body > section:rpt(6) > h Possible definition: The rpt(0n+b) pseudo class is a functional notation which copies the selector up to and including the previous combinator, and is repeated, or multiplied, n times, for any positive, non zero value of n. (If a value of 0 was allowed, it would mean that the selector would be removed) -- Conclusion -- I think the pseudo classes will add a lot of flexibility to the CSS language. Even though my examples deals specifically with the XHTML2 example, there is no reason that they cannot be applied to any form of XML document. CYA ...Lachy
Received on Sunday, 7 December 2003 07:03:14 UTC