How ::selection works on nested elements

To follow up on the group's discussion of the ::selection
pseudo-element at the face-to-face last week (ISSUE-67, see
http://www.w3.org/Style/CSS/Tracker/issues/67 ).  We discussed a
number of possibilities and rejected some of them due to various
requirements brought up.  I'd like to try to go thrtough these
requirements a little more carefully and evaluate potential
solutions.

The requirements that I see are:

  (1) The appearance of a piece of text when it is selected should
not vary depending on the root container of the selection.  (Root
container is a term defined in DOM Level 2 Traversal and Range,
meaning the nearest common ancestor of the boundary points of the
range.)

  (2) The system's default selection style should be representable
in terms of CSS selectors (although we may not currently have
properties for all aspects of the style), in the UA style sheet.
(I'd note that we'd previously considered only one selector for this
requirement, "*::selection".  However, it's possible that we could
use "*:root::selection" instead.)

  (3) Author styles should override the system's default selection
style.

  (4) The background color and foreground (text) color of the
selection style should always cover/override the background and
foreground that apply when the text is not selected.

Also, a very nice to have (almost a requirement), given the current
css3-selectors spec:

  (5) Authors should be able to change the selection style within a
specific element.  (Because of (1), such changes apply to any
selected content inside that element, whether or not the element is
an ancestor of the root container of the selection.)  If they can do so,
such a change should apply to all of the descendants of that element.




Based on these requirements, I can draw the following conclusions:

Given the following styles, markup and selection ("<<" to ">>"):
  p::selection { background: yellow; color: black; }
  span { background: red; }
  <p>This <<has <span>the</span> selection>> in it.</p>
we want the yellow background to be visible inside the span (on top
of the red background), from (4).  This means that the ::selection
pseudo-element must be innermost (i.e., the text "the" is wrapped in
the selection pseudo-element which is in turn inside the span), even
for background-* (which are non-inherited properties).  Making the
::selection pseudo-element innermost also helps satisfy (1).


If we want to in turn satisfy (5), which would require that given
the styles:
  p::selection { background: purple; }
  span::selection { background: blue; }
the background of a selected span inside a paragraph is blue, we
need some mechanism for saying that span::selection overrides
p::selection.  I can see two possibilities:
 * nesting of ::selection pseudo-elements
 * a cascade to create a single ::selection pseudo-element, where
   the rules matching all elements cascade according to normal CSS
   cascading order and according to tree depth

If we choose nesting of ::selection pseudo-elements, then we run
into the problem that the rules:
  p::selection { background: purple; }
  ::selection { background: blue; }
would cause the selection on any element inside the p to be blue.
However, we could still represent the default selection as
:root::selection rather than as ::selection, although this seems
less intuitive to me.

Alternatively, if we choose a cascade to determine the styles of a
single pseudo-element, we would probably want p::selection to
override ::selection on a descendant (in other words, we would make
tree depth a weaker criterion in the sort than specificity, but
stronger than style sheet order).  However, that might be somewhat
non-intuitive when comparing other, more specific, selectors
(p#notice::selection vs.  span::selection).

Yet another approach would be to make tree depth the strongest
criterion in the cascade.  This might be simpler to implement since
it would allow more direct use of existing CSS cascade code (build
the lists of rules for all elements in the tree according to normal
CSS cascade rules, and then concatenate them).  However, this
approach has the same problem that nesting has, in that the default
style would have to be expressed as :root::selection, and a
::selection rule would override p::selection on any elements inside
of p.

I would note that one other major difference between the cascade
approach and the nesting approach is the handling of background
colors with an alpha component between 0 and 1.  In the nesting
approach, the alpha components nest (and thus get more opaque) or
potentially draw on top of a non-alpha selection background color.
In the cascading approach, only one background color would be used.


To summarize, I see three options:

A) nested ::selection pseudo elements (one for each ancestor in tree)
 - introduces fewest new concepts to CSS model
 - handles *::selection badly
 - handles background colors with alpha badly (though perhaps
   depending on requirements)

B) single ::selection pseudo element, cascaded by (tree depth,
weight/origin, specificity, order)
 - handles *::selection badly

C) single ::selection pseudo element, cascaded by (weight/origin,
specificity, tree depth, order)
 - introduces most new concepts to CSS model

In all cases, a ::selection pseudo-element would never contain any
real elements; they would always be split at any boundaries and
created as the innermost position.

I believe all three of these approaches meet requirements (1)-(5).


However, I haven't yet considered the effect of declaring the
'outline' property on ::selection pseudo-elements, which might make
an outermost rather than an innermost pseudo-element desirable,
assuming that supporting 'outline' on ::selection is really a
requirement.

I believe Ian has some pretty detailed tests for ::selection
somewhere; I haven't yet looked into what they require (or, for that
matter, found them, since I'm writing this offline).

-David

-- 
L. David Baron                                 http://dbaron.org/
Mozilla Corporation                       http://www.mozilla.com/

Received on Monday, 27 October 2008 01:21:50 UTC