Re: Proposal: parent selectors

From: "Boris Zbarsky" <bzbarsky@MIT.EDU>
Sent: Thursday, January 21, 2010 7:40 PM
To: "François REMY" <fremycompany_pub@yahoo.fr>
Cc: <www-style@w3.org>
Subject: Re: Proposal: parent selectors

> On 1/21/10 1:12 PM, François REMY wrote:
>> The :has pseudo-class would not be often used for drastical
>> changes. So, we're applying :has on elements of the DOM
>> that doesn't contains many elements. This would 'mitigate'
>> the problem in most of cases since those elements are not
>> often subject to DOM changes.
>
> I'm not sure I follow....
>
> If you use :has, then depending on the structure of your selectors any DOM 
> change anywhere in the document can affect the style of any other element 
> in the document.  So the general solution to have correct styling is to 
> have all DOM changes restyle the whole document.
>
> It sounds like you're proposing a specific optimization to avoid doing 
> that.  What is the optimization, though?
>
>> For the other cases, though, it would be possible to build
>> a sort of cache. When an element is matching a :has rule
>> (or is only failing a :has part) we add it into a cache list. When
>> the DOM is modified into an element included in that list
>
> Or any of it's descendants. Which means that for any DOM modification one 
> needs to check whether the element is a descendant of something in the 
> list, right?

No, you should not check descendant. Here's a sample
that will be easier to understand than my prose :

ul:has(img) > li {
    margin-top: 5px;
}

(the sample is dumb, it's just a show-case)

[<:root>]
    <ul id="a">
        <li>a1</li>
        <li>a2</li>
    </ul>

    <ul id="b">
        <li><img src="b1.png" /></li>
        <li><img src="b2.png" /></li>
        <li><img src="b3.png" /></li>
    </ul>
[</:root>]

The "cache" would contains every element matching "ul > li"
because every of those element could potentially match the
rule "ul:has(img) > li".

At CSS resolution time, only b1, b2 and b2 <li>'s would have the
style applied. But every <li> would be in the list.

If an element (supposedly a copy of b1) is added to #a, we need
to check every child of #a that's in the "cache" list because it's
possible that they now match the :has rule (or that they don't
match anymore if we delete the newly inserted <li> that was
containing the <img> tag).

Here, the cache would thus contains 6 elements. More optimisation
would be allowed to only rerun the CSS matching algorithm when
the DOM change that occued may have effect to the rule. A :hover
added on an element of the DOM should not rerun the ul:has(img) > li
rule, because this would have no incidence.

As I wrote this sample, I must admit it may become a problem if too
many elements are in the list, because it can conduce to many
computations.

> This would possibly work; it could have incredibly bad performance and 
> memory consumption in some cases.  For example any time :has() is used 
> without anything in front of it (since in that case all elements in the 
> DOM end up in the list).
>
> As I said, with enough memory bloat and code complexity one can work out a 
> way to make this not suck in general...
>
>> This would be very efficient, at least if the number of potential
>> elements matching :has rules is kept small. If not, it may lead
>> to a higher memory usage, and sightly slow down the page.
>> But this situation would not occur in 99% of the cases.
>
> I fully expect unqualified :has() usage to be a significant fraction of 
> :has() usage if the selector is implemented.

This use case would be problematic.

>> (BTW, if has-child is acceptable, I don't see any reason why :has
>> would not be acceptable since has-child also break the UA's CSS
>> optimisations.)
>
> It doesn't break them any more than existing selectors like :last-child, 
> :first-child, :nth-*, and :empty already do, to a first approximation.
>
>> Comme use cases would be :
>> p:has(img), form:has(:focus), .contexMenu:has(:hover), ...
>
> So that first one puts every <p> in the document in the list, right? Then 
> every DOM mutation has to check whether any parent node of the thing being 
> mutated is any of those <p>s.

You're true. Optimisation may though detect that if no IMG tag were added
(no removed) the state of the :has(img) will not change for any P. But it's 
an
optimisation. The general case sucks, I must admit it.

Especially if an author choose to perform P:has(:hover) { color: gray; }

Even if an optimisation is possible, it may became very very slow
if the UA impelement it whithout optimisation. Optimisation would be
to listen events on elements that could change the :has status of a query
and only apply a check on those change.

But it will require many difference cases, and thuse an huge amount of
code, which is not very acceptable, too.

> For a typical document (with sections and paragraphs) that means that just 
> the list-checking is comparable in number of operations (though not in 
> memory access pattern, which might help) to walking over the whole 
> document...

Yes, it may end up so.

>
> -Boris
> 

Received on Thursday, 21 January 2010 20:26:47 UTC