Re: [css-props-vals] First iteration of L1 spec

> On 12 Jun 2015, at 02:39, Greg Whitworth <gwhit@microsoft.com> wrote:
> 
> Hey everyone,
>  
> Tab, Shane, Ian and I were able to get together on a video call today and hashed out some of the details regarding what the custom properties and values API can provide, its expected data structures, potential hurdles and some examples.
>  
> Please feel free to provide your feedback regarding the API design and any potential issues we didn’t consider.
>  
> http://dev.w3.org/houdini/css-properties-values-api/

Hi,

This looks fun and very useful. Thanks for getting the ball rolling, and tickling my brain today. Comments:

1) Real properties have a distinct computed value and used value computation phase, which both work differently. If we don't try to reproduce these 2 phases with a fairly high similarity to how browsers do it for native properties, we will be quite severely limiting what you can do with custom properties and you wouldn't be able to emulate / polyfill what native properties do. I don't think this mechanism would count as a primitive in the extensible web manifesto sense, which is what I think we should be trying to expose here.

So I think we need 2 apply hooks: a computeHook and a useHook (or maybe layoutHook, or reflowHook...).

2) For the computed value hook, a model of input and output makes sense, although I'd probably do it a bit differently.

2.1) For some properties, but not all, the computed value depends not only on the computed value of other properties on the
same element (as expressed by inputProperties), but also on the parent element. I'd add an (optional) flag for that.

dictionary ComputeDescriptor
 {
  ComputeCallback computeHook;
  boolean? dependsOnParent;
  sequence<DOMString>? inputProperties;
  sequence<DOMString> outputProperties;
};

When dependsOnParent is true, the computed values of all properties on the parent element (recursively?) would but accessible through the ElementProxy, and not if it's false.

We could live without this, always include ancestors, and you just don't look at things you don't need, but informing the browser about it should allow for parallelism opportunities that wouldn't be there otherwise. Also, not getting access to things you don't intend to use makes your code a bit more robust and easy to reason about.

We could also refine it to try to express which properties on which ancestor you depend on, but that might be overkill.

2.2) I would change this sentence from the explanation of inputProperties:
> If this value is not null, then the apply function is only called for elements or pseudoelements on which the listed properties all have non-initial values.

First, this sentence needs to be tweaked to take into account parent/ancestor elements.

Also, this description makes it sound like this is a process that only happens one, but in fact, you'll need to call the hook every time one of the input property (or ancestor) changes, regardless of whether it's changing to or from an initial or non-initial value.

Then, I would add a clause saying that if a function appears both in the output and input list, then the apply hook gets called even if all the input properties are at the initial value. Otherwise, you cannot have a property which has both:
 - dependencies on other properties for the computed value
 - the initial value computes to something other than itself regardless of dependencies

This should be a fairly rare case, but I don't see why it would be impossible. I can't think of any existing property that has both of these, but each of these does happen, and there is no fundamental reason they cannot be combined.

2.3) In addition to throwing if a property has already been registered for output, since you have enough information in the input and output list to do cycle detection, I would also throw an exception on any attempt to register a computed value apply hook that would introduce a loop.

2.4) Since we're making this explicitely about computed values, the proxy element should not give access to its children.


3) For the used value / layout / reflow hook, I don't think we can simply model things in terms of an input and output list of properties.

If we look at how browsers do this for native properties, it's much more intricate than that. On each element, you have some sort of partial ordering in terms of which property is taken into account after which one, which is sort of like input/output dependencies, but also you need to know if this is a property whose used value is calculated while walking down the tree (like width), or one that is calculated while walking up the DOM (like height). And neither this up/down or input/output ordering are a static ones, they may change depending various things, or be intertwined. And sometimes you need multiple passes...

I haven't though about this long enough to be sure how that can be solved, but I am pretty sure that the current proposal falls short of what we'd need to approach the expressivity of native properties.

4) I think the problem you've called "Elephants in the room" in the spec is much more important to solve for the layout/reflow hook than for the computed value hook. Conflicts at computed value time should be pretty rare, even when mixing polyfills as you don't often need to affect the computed value of native properties. Not saying never, but I think that wouldn't be a major downside. 

On the other hand, it is probably essential that we find a way to avoid this conflict on the reflow hook, as modifying the value of native properties is what a custom property with a reflow hook would need to do in order to take effect.

5) I don't know if we can express solve the reflow/layout hook well without first exposing the box tree / fragment tree.

Let's say you're trying to use custom properties to polyfill hyphenation. You might be tempted to go fiddle with the dom to inject the hyphens and line breaks where you want them, but that would trigger a style recompilation followed by a reflow, and potential infinite loops. Even if you don't, it wouldn't be that simple to undo when the property is switched to another value.

Or let's say you're trying to polifyll regions. Trying to create new fragments by making new DOM elements would get you in the same mess.

All in all, my conclusion is that this is way harder than I thought. Maybe I'm trying too hard to get close to what you can do with real properties, but I am afraid that if you don't do that, advanced polyfills, which should be users of this kind of features, won't be able to use this and will still need to reinvent everything manually.

 - Florian

Received on Friday, 12 June 2015 11:49:07 UTC