- 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