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

NOTE: I really want an issue tracker! For now, I'm going to mark issues
inline in this email so I can find them and file them later.

On Sat, Jun 13, 2015 at 3:47 AM Greg Whitworth <gwhit@microsoft.com> wrote:

> >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.
>
> Yep, we stated as such in the spec as this is one of the drawbacks. I also
> wouldn't say that this is truly limiting as we state that you set a syntax
> that the engine will already understand, a good example of what this would
> provide is the capability to polyfill the often requested 'size' property
> using whatever computational setup you desired (I'll assume it has an
> aspect ratio so saying 100px, would result in a 100x100 box:
>
> Ex:
>
> apply: function(el) {
>         el.outputStyle.width = el.style.get('--size');
>         el.outputStyle.height = el.style.get('--size');
> }
>
> Granted you may want to allow two values or just one and handle them
> separately, all of which you could do. We don't disagree that it would be
> valuable to be able to setup custom computed values, but this is a good
> start. Especially since a lot (not all) of the polyfills are just giving
> support for new props.
>
> >So I think we need 2 apply hooks: a computeHook and a useHook (or maybe
> >layoutHook, or reflowHook...).
>

My model is this:
* there's a compute hook, which in L1 of this spec is not able to be
changed from its default. We can revisit this in a later level, though. For
L1, the compute hook does a 'default' thing (lengths get resolved to
px/percent values, colors get normalized to rgba values, etc.). This
doesn't cover every CSS property available today, but it gets us 80% of the
way which is a good start.
* there's an apply hook, which is the thing that mixes computed values
together. This is configurable. Because values can be computed from several
input properties, this has a slightly different mechanism to what a compute
hook would look like. This hook exists so that custom properties can have
an input on layout and paint by modifying the computed value of 'real'
properties .. just before those properties are used.

ISSUE: The spec should define what the default computation thing is for
each type that is supported.

>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.
>
> Valid point and worth discussing, this adds more complexity and I would
> like to have a good use case for this before we add it in. Can you provide
> an example of something you would like to polyfill that would need this
> behavior?
>

One of our examples already does something like this :) I think it's worth
discussing whether to explicitly require information about parent
dependencies or just generally make parent information available.

ISSUE: work out whether to be explicit about parent access

>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.
>

ISSUE: tweak inputProperties specification to take into account
parent/ancestor elements and make it clear that the apply hook gets called
every time one of the inputProperties changes.


> >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.
>

I think that this would be valuable when we have a compute hook.


>
> Another valid point. Thanks!
>
> >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.
>
> Yep, that's what I was going to state when reading your above statement
> that we should fire all the time. I am also curious though if we should
> throw, or simply set an alert in the console as you may desire for a loop
> of some sort (thinking of custom animations in future versions when we
> figure out the computational part). I'll let Shane handle that though as
> I'm not the expert in animations.
>

Loops are not possible - only pre-apply computed values are readable and
only post-apply computed values are writable. Apply methods can't chain off
each other. This is actually getting towards the Elephant in the Room -
coordination between custom property effects is actually surprisingly hard
to do, unless one or both effects is aware of the other's computation model.


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

Interesting point. I'd like to think about whether it's possible to do any
sort of layout polyfill before custom layouts become available, in that
case.


> >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.
>
> Hmmmmm, again I'm not sure if this complexity is necessary for this stage.
> I'm not against this necessarily, I just would rather keep it simple until
> we hit a use case where someone can't accomplish a polyfill (that's truly
> needed) and can't be helped out by one of the other pieces of Houdini
> (namely custom Layout + Fragment tree).
>
> I may be off base, and please correct me if I am misunderstanding the
> direction, but my expectation is to have a custom layout, that registers
> all of its custom properties and any handling of those for the cascade. But
> custom layout is where a lot of this workhorse stuff you suggest will
> happen, you'll iterate over the datastructure doing your layout (in example
> of height) and continuing to move down the trees creating your structure
> and updating the values as necessary. This will allow for your potential
> need for multipass, I just don't think it needs to be here; but as I said I
> could be wrong.
>

I think we definitely should have a session at the August f2f about the
full pipeline model, because it would be great to draw all these things up
in terms of how they interact with each other .. and then write it all down
in a spec.

My mental model is that width/height computation is layout, and will be
best handled by a custom layout phase. Similarly for other used values.

Layout has very different computation properties to style, so if you try to
do some form of layout using custom properties alone then you can probably
do some simple things but harder things will be pretty much impossible. We
had a go at doing something pretty simple as an example in the spec and you
can see it's already quite horrible.


> >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.
>

When we have a computed value hook I think it should be written in such a
way as to make mixing values impossible. That part should be saved for
application.


> I plan to put an agenda item for the Houdini meeting in August with this
> title. There are problems that just exist based on how the platform
> currently works that we're having to work around that we should discuss.
> What things can we do, and what things should we do? The last thing I want
> to do is provide APIs that technically allow for full custom layout but do
> it in a hackish manner and potentially provide foot guns to developers.
> This is one of them, but I have a few others that I really want us to
> consider.
>

I added a proposed agenda topic to the planning pages for you - I also
think it's really important that we understand the coordination problems
that are going to crop up.


>
> >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.
>

Agreed 100% :)


> >
> >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.
>
> Sure, as all of the pieces of the Houdini puzzle begin to take shape,
> we'll quickly realize that each one has merit on its own, but only when
> combined do you truly find its true power (I'm avoiding to write a cheezy
> Captain Planet cliché here :)  )
>

Our apply hook is different to your reflow hook. We specced apply to be
able to modify computed values of native properties, but not to participate
in things like layout (because that's the job of the custom layout spec). I
think we all fundamentally want to end up in the same place though.


> >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.
>
> We said this many times, and again I think this comes back to needing to
> discuss what fundamental issues exist in the platform that we may need
> other WGs to help out in solving to allow us to make this work how the
> underlying engine works. These may end up not being huge issues, but we
> should at the very least discuss them and how to address them.
>
> Thanks again for taking the time to review the spec :)
>

And a hearty thanks from me too! I'm excited that lost of people are
thinking about this.

Cheers,
    -Shane

>
> > - Florian
>
>

Received on Saturday, 13 June 2015 06:04:42 UTC