Re: Selector for tags with a certain child.

On Fri, Oct 10, 2008 at 10:08 AM, Simetrical <simetrical@gmail.com> wrote:

> On Thu, Oct 9, 2008 at 9:48 AM, Tab Atkins Jr. <jackalmage@gmail.com>
> wrote:
> > The discussion spawned off of that thread [1] between me and Boris,
> though,
> > came to the conclusion that a simple parent selector wouldn't be overly
> > burdensome (a previous-adjacent-sibling selector would be worse, a
> > previous-sibling selector worse still, and an ancestor selector worst of
> > all).  It can cause reflowing, but the damage is relatively limited (to
> only
> > the parent and any siblings+children), and the computational hit of
> > computing matches is minor in this simple case.
> >
> > [1]:http://lists.w3.org/Archives/Public/www-style/2008Jul/0603.html
>
> His answer was kind of noncommittal, I think:
>
> > For "foo:matches(> bar)", if that means "a <foo> which has a <bar>
> > child" that means that in genera we need to reresolve the parent of a
> > node being inserted or removed (plus of course all its descendants).
> > This can be optimized a bit by keeping track of whether such a :matches
> > is around and would have to be, because adding children to an
> > <html:body> is pretty common during parsing.
> http://lists.w3.org/Archives/Public/www-style/2008Jul/0625.html
>
> The basic point is that for DOM appends, you have to re-render one or
> more elements for all these selectors, or else delay progressive
> rendering.  The parent selector could be unpleasant if you were doing
> something like "body:child(div.myclass)" and that got hit late in a
> long document, whatever you do.  Until everyone has a lot more
> CPU/network bandwidth and everything parses instantly, maybe.  :)
> (But "adjacent sibling" is automatically limited to having to
> reflow/delay for only one element, so it's probably more feasible:
> "pretty easy" and "doesn't sound too bad", as Boris said.)


Yup, that's what I got out of it too.  Of course, when an implementor tells
me something would be "pretty easy", I tend to take that as a good sign.
 ^_^  At least when applied to a proposal like this, which has been talked
about like it was impossible for forever.

Yes, any sort of :matches or :child selector hooked off of the body element
would be non-optimal, but honestly, do people really *do* that?  The only
time body shows up in my selectors is when I'm setting the base font details
or the overall background for the page.  I suppose you could try to be fancy
and change the page background based on some element within the page, but
you're really just *asking* for a reflow at that point - a javascript-based
solution would be just as bad.  As well, this scenario becomes even less
likely when you consider that we're only allowing the child combinator here,
so this body-level change would have to key off of the uppermost level of
elements, which is typically just a bunch of containers for the page.

I think a couple of more limited variants could be implemented
> cheaply, though.  For instance, "an X whose *first* child is a Y"
> should be no problem at all: just don't begin rendering the element
> until you've got the opening tag of its first child, which should be
> just about immediately.


That certainly would work.  I'd bet it'd be nearly trivial.


> This might work in a considerable percentage
> of use-cases for a general parent selector.  You might even be able to
> do "an X whose 'first descendant' is a Y", so a hypothetical
> "div:first-descendant(input)" would match the outermost div of
>
> <div><fieldset><input ...></fieldset></div>
>
> again, I hope -- not being too savvy on the implementation of such
> things -- without much cost.  The point would be to not allow any text
> or other stuff that actually needs to be rendered in between the tag
> you're actually matching and the opening tag you're checking for.  You
> wouldn't have to reflow anything, and I'm guessing you wouldn't
> significantly delay progressive rendering.


Hmm, yeah.  This would likely be only slightly less trivial.  One issue with
it is that it's sensitive to empty text nodes as written, which means you're
restricted in how you're allowed to indent your code.  I'd make sure it was
stated that empty text nodes are ignored for this purpose.

I guess you might have to wait a bit longer to start drawing borders
> and so on, things that only depend on the outer element -- you'd have
> to wait for the opening tag(s) of the next element(s) to be parsed.
> But a) it should be a very short wait in any remotely reasonable case
> (yeah, str_repeat( '<div>', 50000 ) would be slow, granted), and b) I
> don't know how common such things are anyway -- in many cases you'd
> have to wait for at least the beginning of the element's contents to
> be able to start drawing any of it anyway (e.g., you can't draw the
> background of a typical empty div, since it will be zero-height until
> it has contents).


Yup.  From what I know of rendering (little, but I learn more every thread),
this wouldn't be an issue.


> What were the use cases given for a parent selector again?  The one
> that springs to mind is things like styling wrappers differently if
> they contain form controls, as in my example above, which this weaker
> (and faster?) variant might well allow in many cases.


In general, styling wrappers based on their content.  In specific, form
controls have been batted around as a common subcase, and I know that I've
written code that would benefit from this for exactly that reason
(specifically, I've many times wanted to style a wrapper based on the
:selected status of its contents).  The limited form of child and descendant
combinators would indeed work well for a majority of cases here.

I suppose that maybe we want to split this off into multiple pseudoclasses,
then.  To start with, we have :first-child() (obviously this is a bit
confusing with the existing :first-child pseudoclass, but are the
parenthesis enough to disambiguate adequately?), :first-descendant(), and
:first-sibling().  All of these take simple selectors in thir parentheses.
 The first two match as you've described here, where the selector has to
match against the very first child, or the very first rendered descendant
(that is, no content can come between the parent and the matched
descendant).  :first-sibling() would just match if the next sibling is
matched, in accordance with my previous proposal for :matches( + div ).

If it is deemed feasible, then, we can introduce a :child() pseudoclass.  It
was said that it's probably infeasible to do a general sibling or descendant
forward-matcher, but if/when it *does* become possible, we can introduce the
:sibling() and :descendant() pseudoclasses as well.  Should these go into
the spec from the start, with the understanding that current UAs probably
won't implement them?  Or is it better to leave them out and add them back
in when UAs say they're ready for them?  If the latter, I recommend a note
in the spec saying approximately that these pseudoclasses, while an obvious
addition, aren't currently feasible to implement.  That should maybe prevent
a constant flood of people asking why such obvious additions aren't in the
spec.  ^_^

So, implementors, thoughts?  :first-child(), :first-descendant(), and
:first-sibling() are probably okay to implement, right?  Any thought on
:child() from the Webkit or IE team?

~TJ

Received on Wednesday, 15 October 2008 15:30:43 UTC