Re: Proposal: parent selectors

*That* discussion again...

Another CSS user asking for a feature, so another proof there is a need for it.
We are getting the same arguments as before (the "too ineficient"
one), and it is as invalid as before.

Fact #1: whatever that can be achieved through jQuery, could be done
faster through a native implementation within the UA.
Proof: jQuery essentially is an API written with an interpreted
language (JavaScript) on top of the native APIs provided by the UAs.
So, whatever a page does through jQuery, it's broken down and deferred
into calls to the UA's API, which in turn performs the task through
the native UA code that implements the API. So, if the UA provided the
feature natively, we would save an indirection step (from jQuery's
APIs to the UA's APIs), plus the overhead of JS code
parsing/interpretation.
Issue: UA vendors are obsessed with absolute progressive rendering,
which on the general case comes more from historical reasons (remember
when we had to wait for an entire page to download over a 14Kbps line
before we could see anything on the screen?) than from a current need.
Sure, for large enough pages progressive rendering can still be
noticed; but even in that case, it's often not enough: big pages often
use complex layout, with an insanity of floats, tables, and what-not
that keep moving around the screen until a significant part of the
page is loaded. Yet, users don't tend to complain about this: they see
that something is going on, and at the end they intuitively understand
that it took a bit longer because of the lot of stuff that's in there.
All of this leads me to the following point:

Question: if :has() (or any equivalent feature regardless of syntax)
was implemented, would it need to take profit of progressive
rendering?
Answer, Fact #2: No.
Proof: Those authors who really need :has()'s functionality rely on
jQuery, so they don't get progressive rendering. It's a trade-off, and
the volume of web authors relying on jQuery are a proof that it's a
good deal on many cases. Even for newbie authors who don't understand
the efficiency costs of this feature, if they have a minimum idea of
what they are doing they'll test their pages on at least one browser,
so they'll get an idea on how fast or slow they load.

Based on the above, here it goes:
Suggestion for UA vendors: implement some version of this feature
experimentally (maybe a limited version, such as the "child" and/or
"next-sibling" versions that have been discussed previously), with
vendor prefixes or whatever, that defers processing of rules using
this feature until the rest of the document has been loaded. The rules
can be flagged for deferred execution as soon as the ":has(" string
(or whatever other syntax they use) is found on the selector, and
elements that would match the part of the selector before ":has("
could also be flagged so style updating after dynamic modifications of
the page can be optimized.

In summary:
- Authors that use jQuery seem to be ok with the efficiency costs of
jQuery's features (otherwise, they wouldn't be using it).
- Whatever that can be done through a javascript library could be done
faster if implemented natively by the UA.
-> Based on the two points above, the efficiency arguments against
:has() (or :matches(), or <, or :has-child(), or any other of the many
syntaxes that have been proposed until now) become worthless. The only
thing I'm asking vendors to do (and without almost no hope of being
listened anymore) is to simply try it, and then decide whether it's
worth or not.

Regards,
Eduard Pascual

On Thu, Jan 21, 2010 at 3:26 PM, Tab Atkins Jr. <jackalmage@gmail.com> wrote:
> On Wed, Jan 20, 2010 at 1:11 PM, Stephen Belanger <cyruzdraxs@gmail.com> wrote:
>> This has probably been suggested before, but I didn't find it in a search.
>> Currently we can find child elements like so;
>> a > img
>> This would return any image contained in a link--but what if you need to
>> select any link containing an image? For that I propose an equivalent that
>> runs in the opposite direction;
>> img < a
>> The css interpreter would start by finding all 'img' elements, then it would
>> try to move one level up and, if an 'a' element is found, would return
>> successful and add that element to the list of elements to apply that
>> particular style to.
>
> Yup, been discussed before.  ^_^  It's a difficult problem, though.
>
> The general case is implemented in jQuery by the :has() pseudoclass.
> You'd write "a:has(img)" to select an a that has an img descendant, or
> "a:has(>img)" to be more specific about where the image is.
>
> Unfortunately, while this is reasonable to implement once you have the
> entire page built and ready like jQuery does, it breaks some very
> important optimizations if you're trying to match selectors to
> elements *while* the page is being built, which is the time when
> browsers do the majority of their selector matching.  Basically, with
> normal CSS you have all the information you need to find all the rules
> that match an element as soon as the element appears; if you start
> from the end of the selector and go backwards, you keep looking for
> parents, ancestors, and previous siblings, all of which occur earlier
> in the code and thus have already been parsed and inserted into the
> page.  :has() breaks this, as it requires information about
> descendants and later siblings, which means you can't match the rule
> to an element until well after it's been parsed.
>
> So, :has() is very inefficient.  It's also very useful, though, so
> it's certain to show up in CSS at *some* point.
>
> For now, though, Boris Zbarsky of Mozilla has indicated that a
> :has-child() pseudoclass wouldn't be *too* inefficient, and so I
> believe it's likely to show up in Selectors Level 4 (we've finished up
> Level 3 already, and are pushing it through the standards track now).
> I think :has-child() covers the majority of use-cases as well - my
> main need for it is "label:has-child(:checked)", and your
> "a:has-child(img)" would also work.
>
> ~TJ
>
>

Received on Thursday, 21 January 2010 16:37:05 UTC