- From: François REMY <francois.remy.dev@outlook.com>
- Date: Wed, 17 Jun 2015 20:50:58 +0200
- To: "Tab Atkins" <jackalmage@gmail.com>, "'Shane Stephens'" <shans@google.com>, "'Greg Whitworth'" <gwhit@microsoft.com>, "'Florian Rivoal'" <florian@rivoal.net>
- CC: <public-houdini@w3.org>
- Message-ID: <DUB405-EAS145E538AD46A95851972951A5A60@phx.gbl>
Thanks Tab and Shane for your replies. I’ll try to give concrete examples to showcase my points below, and reply to your two emails at once (given Shane switched to HTML emails already, I feel less guilty for using colors to differentiate the quotes: blue for Shane, violet for Tab). A few additions I would like to see added to the allowed types are : - "<length-and-percentage>" (accepts "50px", "50%" and " calc (50px + 50%)") - "< ident >" (any custom identifier) - "< ident >(auto, none)" (a list of possible idents which the property does accept) - "*" (any input, much like a unregistered custom property) ISSUE: Add the above types to the spec. It should also probably be flushed somewhere in the sepc that the " initialValue " should match the given "syntax", of course. ISSUE: add this somewhere ==================================== [1] It creates a toxic environment ==================================== Let's say I create a polyfill for the "size" property which is a shorthand for both "width" and "height". That means that no other polyfill can touch those two essential properties anymore. Ditto for any polyfill which wants to handle "transform". Polyfills are going to conflict with each other all the time, making them unusable outside contained demos. That's not sustainable. Yes. It's precisely this that led us to propose 'apply'. Consider the problem from this perspective: how can polyfill authors create new custom properties without having to know about every other intersecting property in the world? As a simple example, take '--extra-margin', which does: width += --extra-margin And '--tile-width', which wants to do: width = --tile-width Depending on the order in which these are registered, you get very different results. It's impossible for us to solve this problem for all time, baked into the browser. Instead we need to make it possible for framework authors to solve subsets of the problem and be flexible into the future. 'apply' exists not to prevent properties from working together, but to force the existence of user-level frameworks that can mediate property conflicts like this. A framework can provide their own registration functionality that takes the functions and converts them into a single coherent per-native-property apply function. I feel extremely unsatisfied after reading this argumentation. The “execution order” issue you outline is something extremely frequent in computer science and which has been sorted out for a long time. Examples includes Jersey’s or WinRT’s Http filters, but also a lot of decorator-driven APIs. Given the order in which polyfills are going to be executed can be defined as the order in which they register (see notes later), and given that this order can be freely altered by the author of the webpage, I don’t see any reason to believe an user-level framework can do anything which cannot be provided by the browser, in this case. Enforcing a framework for the sake of enforcing a framework looks sad to me. Moreoever, requiring the use of a user-level framework (like my own Parallia) at the spec level is something I want to discourage strongly. If polyfills have to cooperate at the user level, it’s pretty clear that the author of the most popular polyfills will somehow force others to use the same framework and this framework will become a requirements for years to come. I, for once, don’t want my polyfill framework to becomes the next JQuery in 10 years, which everyone seems forced to use because plugins depend on it, but it actually provides no value except providing a legacy-inspired interface to technologies the browser provide natively. I want people to be able to innovate in this sector, and by requiring a common user-level framework we clearly are not helping people to innovate. Finally, dealing with other people’s plugins is something that doesn’t look much harder to me than supporting new native additions to the platform. Many plugins or components you’ll find on the web today assume “box-sizing: content-box” to work properly. Adding any new property that affects layout will probably make it harder for polyfills to work properly; whether it’s a native property or a polyfilled one doesn’t make it any different. That’s fine, it’s just a limitation of polyfills that they often can’t work properly with things they didn’t know about when they were made. It’s still possible to use them in contexts that will not trigger these issues, or to adapt the polyfill. After all, you have the source code. I'd be very interested in hearing *how* you think polyfills are supposed to coordinate. Seriously, we have no idea how it's possible to coordinate between properties without the scripts explicitly knowing about each other. There's a killer ordering problem that you can't solve without either (a) the stylesheet author specifying an order they run in the stylesheet, or (b) the scripts coordinating with each other. You can, of course, fairly trivially write a coordinator that takes several apply hooks in order and generates a combined apply hook for all of them. Just union their input and output properties, then run them in the passed order. [...] Having the spec provide such a coordinator might be possible, of course. [However, a script] registration order doesn't work; it means that async scripts cause race conditions. If two things affect the same properties, and have to run in a particular order to work properly, then it might run correctly most of the time on one computer due to network conditions, but fail in production. There’s a trick here. If you look at the steps I propose again, you’ll see that the registration I talk about is a DOMString registration (aka “StyleTransitionController’s types”). As such, this registration should not be done by the polyfill itself but by a script on the page that registers all the polyfills in order and at once [*]. The actual implementation is only created much later, when it’s actually needed. You could potentially require a StyleTransitionController type and find out it isn’t needed on the page so skip its loading. As such, the author doesn’t need to know about the polyfill internals to make the registration, just the name the polyfill needs to have registered in order to work. After that, it’s up to the author to choose the best location in the code to make the actual registration. [*] We may actually enforce this by limiting the registration to one single call accepting an array of strings (or at least we should throw on subsequent registrations trying to register a type that was not already registered during the first call, to ignore redundant registrations made by independent frameworks running after some user code handling the registration). Or we may leave this open and let authors deal with it. After all, it’s their code. I'm not sure why you state the polyfills are unlikely to modify native properties. Polyfills have literally no other option than setting the value of native properties to have an effect on the page, I expect most polyfills to actually work this way, and not by going the full Custom Layout road. Nobody stated this. In fact, all of the examples in the draft we wrote explicitly modify native properties. I think you misread Florian's email, where he proposed an additional stage and stated that writing to native properties *in his new stage* was unlikely. Indeed, it looks like I misread the whole thing; sorry. ==================================== [2] It is insufficient to mimick css properties ==================================== Florian's 2.1: > 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. To restate Florian's 2.1, a fair amount of usefule css properties don't live on their own. Sure, on one hand, a lot of those are affected by the layout phase (which we could arguably leave to Custom Layout), but on the other hand, even properties which do not have a "layout-computed used value" can depend at computation-time on parent state in a non-"inherit" way. Think, for instance, about "justify-self": the ‘auto’ keyword computes to [...] the computed value of ‘justify-items’ on the parent [...] or ‘start’ if the box has no parent. Access to parent styles isn't forbidden in the draft specification. Florian's question was about whether to force authors to specify that they want to access parent styles before enabling it. Okay. That doesn’t seem to be explicitly allowed in the spec either (and usually a spec defines what’s allowed and not what’s not allowed, as that would be an infinite set of things :-D) but I guess that’s just because it’s an early draft. It caused confusion but if it’s just an omission then forget this comment. ==================================== [3] Transitions seem to conflict with the model ==================================== Let's say we have a hook computing "--both-numbers" to the sum of "--first-number" and "--second-number" (if both are specified) or computing "--first-number"/"--second-number" from "--both-numbers" (if one of them is missing)). Now, imagine that a transition starts on hover: element { --first-number: 0; --second-number: 1; transition: really-all 1s; } element:hover { --first-number: 0; --second-number: 2; } Since the css engine cannot know how "--both-numbers" is computed, he has to call the "apply" model on every step of the transition. How will the css engine know whether the computed value for "--both-numbers" should or should not transition normally after the "apply" model is run? I may be wrong, but it seems impossible to know, which means it won't transition (however, since "--first-number" and "--second-number" do transition and the "apply" logic is called again at every step, it will looks in this specific case like it does transition, which is great). One of the following must be true: (1) --both-numbers is a typed, declared custom property using the new draft. In this case it should transition as the system knows how to transition it, and also knows to track its computed value for changes (which is precisely how native properties transition). However, things are going to look terrible because you're transitioning both the property and the things that the property is calculated from. Don't do that :) (2) --both-numbers is a Custom Properties level 1 style property. It doesn't transition because it can't. (3) --both-numbers isn't a property at all, but an internal abstraction. Obviously it can't transition in this case either. But I also have to ask what --both-numbers is supposed to be for? Given the current model, it can't effect anything (you can't set up chains of action using apply). Now, the issue happens when you need to handle the real final value of the properties to compute the final value of the computed property, and you want this property to transition normally between those two extremes. This is the case for instance, you set a flag that changes the meaning of some other property, but want the effect of this flag switch to happen gradually (example: a grid where items would move from their old to their new grid area in a transitioned way and not directly like we do now). Since you don't know how far you are in the transition, that's not possible. The only way you can control the position of things with this approach is by controlling their top/left, or their transform. Both have wonderful transition behavior already. Please note, by the way, that this is just level 1. We need a minimum viable subset that solves some real problems now, and is also extensible. ----------------------- It's not clear to me what your proposed model is trying to solve. Can you provide some clear examples of things that your model would enable which can't be supported by the current approach? We could start with the --first-number / --second-number example above, but we need: * some kind of effect (what does --both-numbers exist for and what does it control?) * an example script showing how this would be supported using your model * one or more example timelines of inputs and outputs that you think aren't achievable using the current draft. Cheers , -Shane As you noted, if I want to animate the location of an object on the screen, I can use “transform” which transitions perfectly fine. The issue is that the “apply” hook will be run *after* transitions already took place. So, any change I’ll make to “transform” in the hook cannot possibly rely on the “transition” property to animate. That’s my issue at this point. You’ve also no way to know a transition is in progress, and use this info to precompute the next frames while the browser is idle, for instance. Like Tab said, it will be necessary to provide some insight about transitions anyway to the “apply” hook, which is why I call it a “StyleTransitionController”. Also, polyfills will want to allow transitions from/to “auto” or “none” values, which is why I believe since we have to provide the “StyleTransitionController” with “from/to/currentTransitionPoint” for all properties which have been updated or are transitionning. Here’s something else I might want to do: a lightweight multiline layout with fixed-height variable-width boxes which relies on a “StyleTransitionController”, “position: absolute” and “transform” to work. Some custom properties controls the visibility state of items, and when the position of an element changes, I want to be able to initiate a transition between the original location and final location of the items, following the “transition” property normally % the “transform” property (so it may be ‘none’ for no transition, or ‘ease-in 3s’, or anything else). If I initiate some transition, I want a polyfill further down the road to be able to see the transition going on and interpret it (so if I set a transition between “20px” and “auto”, the second polyfill may actually map this to a transition from “20px” to “50px” by precomputing the auto value. Here’s how it would work with StyleTransitionControllers: - The first controller detects that the position of some items must change. It overrides the “transform” property from “<old-value>” to “transition(<old-value>, <new-value>, <transform>, 3s ease-out, 0%)”. - If there would be no other controller, the browser would detect here that the “transform” property should transition and will add the relevant transition. If “transform” is used for input of some controller, those will be called on later frames since the browser will update it using its normal transition behavior. That’s for the basic case. Now let’s imagine there’s a second controller (that’s maybe a L2 feature). - The second controller receives the values as defined by the previous controller. Its purpose is to redefine how transitions work for “transform”, because the matrix-based transition doesn’t work for the author for some reason. So it sees that the “transform” property is going to transition and decides it want to inform the browser not to use a known interpolation algorithm to do the transition. It can set “transform” to “transition(<old-value>, <new-value>, <custom-transition>, 3s, 0%)” instead, and let the following controller or the browser take the focus. - When the browsers see this transition request for the first time, it starts a 3s transition and uses the old value because 0% implies it, but it notes it can’t make this interpolation. So, on the next frame, the browser will provide “transition(<old-value>, <new-value>, <custom-transition>, 3s, 2%)” as input to the StyleTransitionControllers and the second controller (that knows how to deal with the value) will set transform to an intermediate value between “<old-value>” and “<new-value>” using its own custom algorithm; if it did leave the “transition(<old-value>,…,<custom-transition>, 3s, 2%)” value as is, since the browser cannot apply the transition, “<new-value>” is used directly (like if there was no transition going on). So, in fact, the only time the browsers understands “<custom-transition>” is the first time at 0% to initiate the transition and at 100% when it ends. But it can keep the info about the algorithm and give this back to the StyleTransitionControllers which could remap the transition to something the browser can understand. - A big advantage here is that if the transition should stop (property updated again), the browser can use the output value of last frame as the input value of the next frame and provide “transform: transition(<last-intermediate-value>, <new-value-2>, 9s ease-out, 0%)” to the controllers on the next frame. Browsers can also know how to rewind a transition by decreasing the percentage. I don’t know if this was clear. This is harder to explain than I initially thought it would be, so don’t hesitate to ask for more info if anything isn’t clear. Don't gender the CSS engine, that's weird. ^_^ It's inanimate, and so "it" is the correct pronoun. Sorry Tab. As you probably know, “it” doesn’t exist in French and every noun has a gender. It’s a mistake you’ll see me doing a lot, please bear with it. I promise I’ll pay extra attention to it, but there’s only so much attention you can give to an email and this one certainly exceeded it :)
Received on Wednesday, 17 June 2015 18:55:06 UTC