-
Notifications
You must be signed in to change notification settings - Fork 676
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[css-cascade] Additive CSS #1594
Comments
Still relevant on the topic: I have some more thoughts that are not reflected in this 4 years old thread, most notably the role custom properties could have here to improve DRY, but I would happy to discuss this further at the F2F. |
I wish I had more time to dig into this, but I wanted to chime in briefly... I fear that this feature won't really address the pain points that animators face in their day-to-day work. Here are 2 quick demos of where I think it might miss the mark:
(Read the comments in the JS code) I'd LOVE to be able to tap into these technologies under the hood in GSAP, but from what I understand, it doesn't appear as though this feature will deliver what we really need in order to do that. Layering things on top of each other might help in some scenarios, but there are quite a few (as demonstrated above) that still seem to be impossible/cumbersome. Or perhaps I'm just missing something(?) Please forgive me if I botched something in the implementation. |
@jackdoyle Thanks for the use cases, they seem relevant. Here's a similar thing written using the solution I proposed:
Now you can add classes State1, State2 and State3 in whichever order you want and get a deterministic transition. The way this works is that the subtransforms will always be sorted by number sequence, in descending order. That means "1000 2 0" (GSAP_TRANSLATE 0) will always be first, "1000 0 1" (GSAP_ROTATE 1) will be second and "1000 0 0" (GSAP_ROTATE 0) will always be third. You can override these values later in your stylesheet if needed by referencing their list-id:
I also have a proposal to allow you to leave out the last number as a automatically-unique value (you cannot override it later like I did with State1 and State1b, but its relative ordering will be solved automatically using css cascade order)
Last but not least, this gives a lot of flexibility when you need mixing frameworks: If there is another framework, you can (as an author) decide in which order the operations of these frameworks should take place. For instance, if this framework ("ANIMF") should take place after GSAP you can ensure it uses
and if you want to run its effects before GSAP
but you can also have its effect run during GSAP Scale phase
Since variables cascade you can even decide that element per element by redefining GSAP and ANIMF per element. If you need some operations of ANIMF to happen before GSAP but others to happen after, you can use
|
@jackdoyle I'm pretty sure you can address that use case when we add the proposed composite order control. |
Sorry about the late response. For some odd reason, I wasn't notified of your replies, nor am I allowed to subscribe to the thread (even now). @FremyCompany I can't mock up that solution in a codepen because those features aren't implemented in any browser yet, right? I read through your suggestion several times and I couldn't grasp how this would solve the problem I was pointing out. Likely because of my own cognitive deficiencies :) A demo would be super helpful (though I realize it's probably not possible today). @birtles I'm in a similar situation. Does the proposed composite order control allow folks to, for example, have 100 different elements flying around and randomly choosing various translateX/translateY/rotate/scale values with completely different timings without a bunch of overhead that tracks the order of previous transforms? For example, with this additive stuff, after animating to rotate(180deg) how can I get back to 0deg without tracking previous stuff? It seems I'd have to do rotate(-180deg) in order to cancel out the previous rotate(180deg), right? If there's a translateX(100px) and halfway through that, I need to animate translateY(200px) (without interfering with the translateX()) but previously there had already been a translateY(500px) applied, how can I ensure that it arrives at translateY(200px) instead of translateY(700px)? Would I have to getComputedStyle() and parse through the current values? What if it was part-way through a translateY(500px) animation (thus getComputedStyle() won't return the destination)? How much work will it be for the average developer to animate to absolute translateX/translateY/scaleX/scaleY/rotate values with completely offset timings from each other (overlaps)? Got a demo of how this will solve that problem? It'd be super cool if you could fork the demos I provided and show me what you mean. Please forgive my slowness. |
Hopefully I've restored Jack's comment which I accidentally edited. Sorry about that. (And I find it quite odd I can edit someone else's comment!) |
Yes. Obviously if they are different elements, then they have separate composite stacks so there should be no conflict. Within a single element, you can call
You can animate the
Yes, if you're looking to animate the components independently in a pseudo-additive fashion like that despite the fact that they are expressed by the same CSS property, then, for now, you'll need to go through the result of There's some complexity but I think it's manageable and only present when all of the following are true:
If we find that this is common enough, then we can split off separate properties for the independent components that need to be animated in this way. |
(I'm reading through the proposals & comments, so I'll be making a series of comments on separate points. Overall: I really want this feature in CSS!)
This is a very misleading summary. SVG/SMIL has two types of additive animations, yes: multiple independent animations adding together ("additive" animations) versus a single animation that increases its effect on each repeat ("accumulate" animations). Only certain data types are additive (number, length, angle, color, x-y pairs, and transformations). However, they normally behave identically as far as how the addition is calculated, regardless whether it is addition from separate animations or from repeats. The only time there is a difference is for Example of accumulate and additive animations, for Presumably, if you used Edited to add: SVG/SMIL also has an additive animation option that is so super-simple I forgot about it: the |
Definitely the most common, but here are some others (remembering that we're not only talking about one animation adding to another, but also about animations adding to the base value):
Unlike with transforms, creating an additive effect with nested |
General thoughts on the This is one of the most straight-forward proposals I've seen for allowing partial or additive CSS declarations, which is a definite bonus. It fits nicely into CSS syntax (finally something else that uses The main thing that would need to be worked out is the addition rules for different data types. This would be similar to how we have interpolation rules for data types -- and with the similar understanding that some things can't be added and would be replaced instead. The simplicity could be a limitation when talking about more complex properties. For property values that consist of more than a single value, there usually wouldn't be a single universal way to define how to add two declarations. For some cases, this issue could probably be avoided if you could build up that complex value from custom properties, and then animate the custom property values in an additive way. This could be a solution to Brian's filter example. Normally, filters could add by adding an extra filter function at the end of the chain. But you could declare a But there are other cases where you want to modify a complex value, which can't easily be deconstructed into custom properties. For example, to insert an image layer into a For the specific issues Brian highlighted:
I think accumulate is useful. But it doesn't fit into the (I'm assuming that, for If you wanted to support accumulative repeats in addition to an However, there would still need to be details to figure out:
Now we're getting into the complicated questions that the simple syntax can't cover. Which other combination options you want would depend on the specifics of each property type. The more complex the property, the more different possible ways you might have for combining values. Think of two A simple syntax like
This would be very desirable. It should be similar to (This is probably it for me tonight. Sorry I didn't get a chance to review @FremyCompany's proposal. I'll be reading over the IRC minutes when I get online tomorrow.) |
How is that misleading?
Isn't that precisely what the summary says?
I don't know why that is the assumed behavior. (For what it's worth, as the implementer of SMIL in Gecko, the distinction between these two types of addition was very surprising and was only revealed by a single test case in the SVG 1.1 test suite that failed when I used the same definition of addition across the board. The spec does not make this distinction obvious at all and arguably it only existed in the test writer's interpretation. I don't think anything can be assumed about how it ought to work from the SVG spec. One motivating reason for choosing the component-based addition for accumulation in Web Animations is to avoid creating a very long list for repeating animation.) |
Yes, I am working on adding that to CSS Values & Units since we already use this in Web Animations.
I'm optimistic we can solve this (we have most of these complex types adding together in Gecko / Servo / Blink) by doing addition on the components. There are some cases where we fall back to non-additive just like for interpolation there are some cases where we fall back to discrete animation. As with interpolation, I think we can probably fill some of these gaps in the future without breaking content.
Right.
Web Animations lets you use the accumulate behavior (i.e. adding the function parameter values rather than appending to the list) when adding independent animations.
Right. This per-keyframe additive behavior is already specified in Web Animations and implemented in Firefox and Chrome (but not shipping yet).
I assume this is referring to how to apply accumulate behavior? If so, then this proposal is simply putting forward accumulate behavior as another type of addition independent of repetition.
This is precisely the difference between |
The CSS Working Group just discussed
The full IRC log of that discussion<dino> Topic: Additive CSS<fantasai> ScribeNick: fantasai <birtles> https://github.com//issues/1594 <fantasai> birtles: This issue covers everything I want to say <fantasai> birtles: Want to introduce idea of addititve CSS <fantasai> birtles: Figure out if we want to do this soon or not <fantasai> birtles: We have something like this in Animations, wanted to see if we should pursue in static CSS also <fantasai> birtles: Start off with additive animation <fantasai> birtles: then static additive CSS <fantasai> birtles: Normally when you have animations in CSS <fantasai> birtles: basically you can only ever have one animation affecting the same property at the same time <fantasai> birtles: This demo here has animations spin and swell <fantasai> birtles: when I apply the both <fantasai> birtles: you can see only the swell animation is taking effect <birtles> http://slides.com/birtles/browser-animation-2017-2#/3/11 <fantasai> birtles: This can be due to the nature of the cascade, only one animation declaration will win <fantasai> birtles: But even when you specify two animations in a isngle declarations <fantasai> birtles: then the declarations in the keyframes could override each other <fantasai> birtles: Problem in animations <fantasai> birtles: There's a means for solving that which comes from SMIL <fantasai> birtles: and is in Web Animations <fantasai> birtles: where you define the properties as being addititve <fantasai> birtles shows demo with Web Animations that shows spinning and growing at the same time <fantasai> glazou: Do you put composite=add on both of them? <fantasai> birtles: only the top one <fantasai> birtles: If you declare an animation as additive, then it adds to underlying unanimated style, or adds to underlying animations <fantasai> birtles: wherever in the chain doesn't say add, clobbers earlier declarations <fantasai> glazou: animate(composite=add) that's ok <fantasai> glazou: but for properties... <fantasai> glazou: parsing is not done yet? <fantasai> birtles: That feature is defined in Web Animations, implemented (but not shipping) in Chrome & Firefox <fantasai> birtles: Property for CSS Animations 2 to give same feature <fantasai> birtles: How does it actually work? <fantasai> birtles: different animations types, define what it means to add animations <fantasai> birtles: then need to define order, since not operations are commutative <fantasai> birtles: and also need to know which to exclude <fantasai> birtles: Web Animations there's a defined order <fantasai> birtles: but for CSS Animations the order of the animations comes from the 'animation-name' property <fantasai> Florian: If you're trying to add things that are not additive, what happens? <fantasai> birtles: Just as with interpolation, there are some types are not interpolable and we fall back to discrete <fantasai> birtles: for types we can't add, we fall back to replace <fantasai> Florian: Is this stable? Are there things that we could add in the future but can't right now? <fantasai> Florian: e.g. auto + <length> <fantasai> birtles: Yes, and there is this problem also with interpolation <fantasai> birtles: Our hope with interpolation is that filling in gaps won't break content, we don't know but we hope <fantasai> birtles: so in this case also hoping <fantasai> fantasai: I think switching from replace to add is more likely to break that switching from discrete to gradual interpolation <fantasai> Florian: in JS, could throw an exception, but not in CSS <fantasai> birtles: Amelia had a concern about defining addition <fantasai> birtles: THere are different ways to add things <fantasai> birtles: e.g. blur(2px) + blur(5px) <fantasai> birtles: is it blur(2px) blur(5px) (sequence) or blur(7px) <fantasai> birtles: Web Animations has two different modes of addition <fantasai> birtles: add and accumulate (corresponding to above, respectively) <fantasai> birtles: For most types they're the same operation, but for list types are different <fantasai> birtles: I think Amelia was concerned because accumulation in SMIL is used in repetition <fantasai> birtles: but here it's just another type of add <fantasai> melanierichards: You mentioned that if you get to something that doesn't add, does it replace all the values added up below it <fantasai> melanierichards: [gives an example] <fantasai> birtles: overrides sum up to that point <fantasai> birtles: Add means "add myself to what's beneath me" <fantasai> birtles: You have a stack with A at the top and D at the bottom <fantasai> birtles: A and B are additive, C and D are not <fantasai> [discussion of what ordering means] <fantasai> dino: Don't say it's a stack. Everything is a list. THe last one wins <dbaron> so this would be like animation-name: D, C, B, A. <fantasai> birtles: The result of that would be A + B+ C <fantasai> dino: And if A wasn't additive, then result would be A <fantasai> birtles: And if all additive, then you get A+ B+ C+ D+ underlying style <fantasai> Florian: When you're switching into another style, add to the top of the stack, which can override those beneath it <fantasai> birtles: This proposal suggesting that if we expose in regular standard CSS, then the ordering comes from the Cascade <fantasai> birtles: if you have something of higher specificity, takes precedence <fantasai> dbaron: There are two different mechanisms proposed here <fantasai> birtles: Why have this to begin with? <dbaron> github: https://github.com//issues/1594 <fantasai> birtles: The most common use of additive animation is for combining transform animations <glazou> q+ what about !important in such an addition <fantasai> birtles: to some degree can already do that with separate transform property in L2, where we have translate+rotate+scale properties <fantasai> birtles: Sovles a number of use cases, but doesn't solve all of them <glazou> q+ to ask about !important in such an addition <fantasai> birtles: If you wanted independent animations of the same operation, doesn't allow you to add those <fantasai> birtles: Doesn't help with other things like filters <fantasai> birtles: Any cases where separate transformatoins are not split out enough in our syntax <fantasai> birtles: The other way to solve these problems currently is to add another <div> wrapper element. Not very appealing when you have a lot of transforms <fantasai> birtles: So that's a summary of additive animation <fantasai> birtles: It's in Web Animations spec atm because the scope of Web Amnimations was to cover all the features of CSS Animations, ? Animations, and SMIL <fantasai> birtles: And SMIL already has this feature <fantasai> birtles: My next proposal is a straw man for providing the same functionality in static contexts for regular CSS, not just animations <fantasai> birtles: Here's an example of combining filters <fantasai> birtles shows off examples in the issue <fantasai> birtles: Some potential use cases <fantasai> birtles: proposal is to add a !add to the end of the declaration <glazou> q+ to mention variables for the first Part 2 use case 'filter' <fantasai> birtles: ordering is given by the cascade <fremy> q+ <dbaron> q+ to talk about !add as only being for list-valued properties <fantasai> birtles: Not a fully fleshed-out proposal, just a rough idea <Rossen> a? <Rossen> q? <fantasai> birtles: Last question is whether to ship additive animations as specced or wait to line them up with these other features <Zakim> glazou, you wanted to ask about !important in such an addition and to mention variables for the first Part 2 use case 'filter' <Myles_> q+ <fantasai> glazou: First, about your use case, about the filter property <fantasai> glazou: This is easily doable with variables <fantasai> glazou: Not for an unlimited number of classes or inputs, but if you know the scope of the styles you can get fairly doable with variables <fantasai> glazou: Using !add would allow some cases <fantasai> glazou: Next, !important, how does that interact with this? <fantasai> birtles: !important continues to affect where it appears in the cascade <fantasai> dbaron: I've wanted to have additive cascade for a long time, just didn't have a good syntax for it <fantasai> dbaron: Normal cascading order is that you have a set of declarations and the last declaration wins <fantasai> s/set/sorted set/ <fantasai> dbaron: [describes something I missed] <Florian> q+ <fantasai> glazou: What would happen to APIs that climbe the cascade and find *the* rule that wins? <fantasai> birtles: which APIs? <fantasai> glazou: Inspectors in borwsers <fantasai> birtles: Any Web-facing APIs? <dbaron> s/[describes something I missed]/The cascade just produces a sorted list of declarations. With !add, instead of taking just the highest one for a property, you'd take all of the highest ones down to the highest that doesn't have !add./ <fantasai> s/APIs/APIs affected/ <fantasai> fremy: there's a depreciated API in Chrome <fantasai> glazou: So browsers internally will have to update something, so OK but be careful <fantasai> birtles: inspector also shows which ruels were clobbered <fantasai> fantasai: So you'd have an ordered set of declarations that win, not just one <glazou> ack glazou <Rossen> q? <fantasai> Florian: If you getComputedStyle or some similar thing that give syou the computed value <fantasai> Florian: when something has been added <fantasai> Florian: do you return calc()? what do you do? <fantasai> birtles: Depends on the case <fantasai> birtles: similar to interpolation <fantasai> birtles: e.g. adding % and length, get a calc <fantasai> dbaron: A lot of these are lists, which would append items <fantasai> astearns: Do you get !add in the computed value? <fantasai> No <fantasai> dbaron: There's always a lowest value <fantasai> astearns: might have !add <Rossen> q? <fantasai> dbaron: then there's nothing to add to <Rossen> ack fremy <fantasai> fremy: There are two different proposal in this proposal <fantasai> fremy: There's list-accumulating behavior, which I and Tab have been discussing <fantasai> fremy: This is reasonable to add to browsers, and solves most of the use cases <fantasai> fremy: There's another proposal for things like auto + 50px <fantasai> fremy: That's a different propsoal <fantasai> fremy: I think thses are two very different proposals <Florian> q+ <fantasai> dbaron: This is one of the things I wanted to raise as well <fantasai> fremy: At least in this WG there are ppl working on list things, I thin kit's easier to get there <fantasai> fremy: trying to transform all properties into this kind of list thing isn't something that we are ready to do yet <fantasai> astearns: Showing that we might wnat to go there is useful though <fantasai> birtles: This is implemented in Gecko, Blink, Servo, for more than just these types <fantasai> birtles: The ability to add different CSS types <fantasai> TabAtkins: in Web Animations <fantasai> fremy: I would be curious to see test cases <fantasai> fremy: Still, should be mentioned they are two different things <fantasai> fremy: Another thing I dislike !add is that it's mpossible to redefine a value <fantasai> fremy: e.g. you have filter: blur(val1) ??(val2) <fantasai> fremy: You can add to the list, but you can't alter preivious values in the list <astearns> I thought "filter: blur(val) !important;" would override <fantasai> Florian: You can always wipe out the entire list <fantasai> astearns, yes it would <fantasai> TabAtkins: At that point, you should use variables <fantasai> TabAtkins: variables allow coordinated substitution <fantasai> TabAtkins: uncoordinated addition is what we have to solve here <fantasai> fremy: Other concern is that ordering matters, e.g. transform + rotate and roate + transform are not the same <fantasai> fremy: it's a problem with web animations atm <fantasai> fremy: We have this problem with ppl making websites where everybody is screaming the highst z-index <fantasai> birtles: For Web Animations there's no number <fantasai> fremy: People wnat to control the order, and !add will follow the cascade order <fantasai> fremy: I think for lists, there are better ways to approach this problem with more control <fantasai> fremy: plain !add for list is not good enough <fantasai> fremy: When you are programming, used to being able to modify values and that's something not there, and I think it's really important <fantasai> astearns: Seems to me that you could fiddle with selector specificity <fantasai> fremy: specificity isn't always correlated with priority <fantasai> dbaron: Animations are one of th emore complicated cases <fantasai> dbaron: There are a bunch of other list-valued properties where you really want to combine <fantasai> dbaron: E.g. for counter properties, generally would prefer to have declarations combine, ordering doesn't matter <fantasai> fantasai: Stuff in text decoration also <fantasai> TabAtkins: a lot of properties are sets, not lists, order doesn't matter <fantasai> fremy: My proposal would be ot use an array syntax <fantasai> fremy: And you could put a number as the arg, or a name <fantasai> fremy writes some declarations <fantasai> transform: translate(0px, 0px) <fantasai> transform[zoom]: scale(1.1); <fantasai> transfomr[rotate]: rotate(180deg) <fantasai> transform[hover:100]: scale(1.0) translate(0px, 0px); <fantasai> transition[]: transfomr[hover:100] 0.5s eas-in <fantasai> birtles: We already have seaparate properties for rotate and zoom in Animations L2 <fantasai> Rossen: So your feedback is there's no way to have selection and authoring of the list after initial decl <fantasai> Rossen: anything else? <fantasai> fremy: Also that cascading order is not always the orde ryou want to ocncatenate <fantasai> fremy: There's also the issue of coordination between frameworks <fantasai> fremy: If there's no way to coordinate other thandefining / redefining variables, then they can't coordinate <fantasai> fremy: You can't solve that problem with variables <Rossen> q? <fantasai> dbaron: Few comments <Rossen> ack dbaron <Zakim> dbaron, you wanted to talk about !add as only being for list-valued properties <fantasai> dbaron: One is that there are two separate pieces to birtles' proposal <fantasai> dbaron: I see these as independent <fantasai> dbaron: I se reasonable to do one and not the other in either way <fantasai> dbaron: Either one would get us some good benefits <astearns> I expect that if you're trying to allow more than one framework to compose animations you're going to have a lot of problems <fantasai> dbaron: But I think they are two independent things <fantasai> dbaron: When you start having multiple declaration of animations / ? <fantasai> dbaron: One is about combining declarations, the other about combining animations <fantasai> dbaron: I think as far as the cascading pieces, bits about combining declarations <fantasai> dbaron: I think one of the reasons I prefer something simple here is that I think something like !add or something like that <fantasai> dbaron: It's simple neough, if we can agree on a syntax, it's feasible to implement within existing engines in a reasonable amount of time <glazou> q+ <fantasai> dbaron: I think fremy's other proposal has a lot more complexity, and I'd be more hesitant to go down that path <fantasai> fremy: I'm not arguing for names, I'm arguing for numbers <fantasai> dbaron: There's a bit more complexity there, although a little... I don't know <fantasai> dbaron:Other comment <fantasai> dbaron: Like fremy, I saw this as being only for list-valued propeties <fantasai> dbaron: I see that SMIL has more general mechanisms, and I have mixed feelings for having those in the same system <fantasai> dbaron: It's pulling in a big part of SMIL to pull into CSS, to do addition of other than comma-separated lists <fantasai> dbaron: Other small comment is that in that middle example, I would expect animation-composit itself ot be a list-valued property <fantasai> dbaron: And therefore I would expect that second lne to be animation-composite: add !add; <fantasai> dbaron: Because I think you want to add youre animation-composite value to the list, not replace the list <Rossen> ack Myles_ <fantasai> Myles_: I have a couple points <fantasai> Myles_: One already made iwhich is 2nd piece of proposal can be used in many places <fantasai> Myles_: We've gotten lots of request for ppl to turn on various font features <fantasai> Myles_: and this makes that easier <dbaron> fantasai: font-variant rather than font-feature-settings <fantasai> Myles_: in WebKit we have an issue with text-decoration <dbaron> (but it's worse for font-variation-settings!) <fantasai> Myles_: If parent says text-decoration: underline and child ses text-decoration: strike-through <fantasai> Myles_: In both of those examples, the addition occurs down the DOM, not across cascade <fantasai> dbaron: One of the cases we discussed is what happens if you have adds all the way down <fantasai> dbaron: If you do adds all the way down on an inherited value <fantasai> dbaron: you add to the base value, which ofr inherited properties is the inherited value <Rossen> q? <dbaron> s/inherited value/inherited property/ <dbaron> (the second last one should be substituted) <fantasai> Myles_: Other comment was on pulling apart a list and inserting stuff in the middle <fantasai> Myles_: Issue of different teams trying to coordinate, this is difficult for a company <fantasai> Myles_: we already have two different ways for differnet areas of a document interact <fantasai> Myles_: The cascade through specificity, and then inheritance through document tree <fantasai> Myles_: adding yet another way seems complicated, seems better to re-use existing ones <fantasai> Myles_: Another comment <fantasai> Myles_: You had na issue of adding values <fantasai> Myles_: I fyou have line-height: 50px and line-height: normal, how do you add? <fantasai> birtles: For some we use calc(), but some things can't add and thos efall back to replace <fantasai> birtles: In our impl, the function that does interpolation is the same as the one that does addition <fremy> q+ to reply to Myles with new idea <fantasai> fantasai: On that topic, if we have only the list-valued addition for now <fantasai> fantasai: That's avoids the problem of forwards-compat for types that we can't add yet <fantasai> s/add/add (or interpolate)/ <dbaron> Florian: so if you restricted to list-valued properties, then !add would be a syntax error for other properties? <dbaron> fantasai, dbaron: yes <fantasai> fantasai^: I think switching from replace to add is a more likely compat problem than switching interpolation from discrete to gradual in the future <Rossen> q? <fantasai> birtles: I feel a bit uncomfortable drawing a line between list types and non list types <fantasai> birtles: in implementation terms there's no distinction <fantasai> birtles: For an author that you can add translate(200px) to translate(200px) but can't add margins of 200px, seems awkward <Rossen> q? <fantasai> birtles: Also ... <fantasai> Florian: Less likely that people wil use something that gets thrown out and is a syntax error (though still possible they leave it in the stylesheet, less likely) <fantasai> Florian: than if it has a particular behvaior (replace) and we wnat ot hcange it later to add <Rossen> ack Florian <fantasai> Florian: Not an objection, but a concern about the compat path <fantasai> Florian: This allows things that were impractical <fantasai> Florian: but also is same as using calc() in some cases <fantasai> Florian: I'm a bit worried about cases of e.g. Chrome shipping way earlier than other impls and authors relying on it and it being broken in other impls <fantasai> fantasai: This is an issue with every major feature we add to CSS, can't decide t ojust not add things <fantasai> glazou: I'm a bit surprised we're using !add <Rossen> o+: <fantasai> glazou: Woudl prefer property+:value <glazou> no <fantasai> dbaron: would love property += value, but we're not using = :/ <Rossen> q? <glazou> would prefer +property <Florian> +prop: value / prop+: value <fantasai> fantasai: +property:value ? <Rossen> ack glazou <Rossen> ack fremy <Zakim> fremy, you wanted to reply to Myles with new idea <fantasai> fremy: I'm OK to not have ability resort stacking order <fantasai> fremy: But I want ability to give added values different weights <fantasai> s/weights/timing rates/ <astearns> property: value +add; <fantasai> fremy: I want to say that "for this part I just added, I want to transition the addition at a different rate" <fantasai> Myles_: For font-features that has no relevance, so this feature should be scoped appropriately <fantasai> birtles: I would liked to get a go/no-go for shipping additive animations <fantasai> birtles: and also to gague interest with regards to refining the static CSS proposal <fremy> btw glazou dbaron: my syntax proposal is { transform[]: added-value; } <dbaron> s/gague/gauge/ <fantasai> fantasai: I have no idea about Web Animations, but the additive cascade is something people have wanted to have for a long tme, and it seems like your proposal has a lot of interest from the people here <fantasai> fantasai: No idea how long it'll take but there's interest :) <TabAtkins> fremy: For poking at individual entries of a list, we have the proposal for list-indexed sub-properties... <fremy> astearns: yes; could be a different feature really, just want to make sure we think about a path forward ;) <fantasai> birtles: We have same compat questions for the animated version of the proposal, shoudl they block us from shipping additive animations or are they less sever in the case of Web Animations? <TabAtkins> fremy: Just need to add commas to the transform syntax, to let it become a comma-separated list. <dbaron> fantasai: Was a suggestion to throw exception for things you can't add. <dbaron> fantasai: We can't do that in CSS syntax. <fremy> TabAtkins: yes, could work <dbaron> birtles: probably worse for compat, since first browser to ship will see unhandled exceptions <dbaron> fantasai: if we can throw exceptions for use cases and remove later, less concerned about compat <dbaron> q+ <dbaron> fantasai: if chrome ships auto+100px working, it's because they've figured out how to make that work, and everyone else will want to make that work <fantasai> dbaron: I guess I mostly disagree with fantasai's comment on exceptions <fantasai> dbaron: I think the two things are mostly indpenednet, and I don't see a problem with animations stuff moving forward if additive cascade doesn't <fantasai> birtles: What we have in the spec is a definition of addition for each type, that needs to be written before shipping <fantasai> birtles: pretty simple though <dbaron> s/fremy:/fremy,/ <dbaron> s/TabAtkins:/TabAtkins,/ <fantasai> birtles: additive animations implementation <fantasai> birtles: go forward, assumign test suite / compat etc. <fantasai> RESOLVED: No concerns wrt shipping Web Animations <fantasai> fantasai: Do we want to conclude something on additive cascade? <fantasai> RESOLVED: CSSWG is interested in working on additive cascade proposals. <dbaron> fantasai: can someone draft an ED? <dbaron> alan: I think it's premature to put in a spec. <fremy> ScribeNick: fremy |
After reading @AmeliaBR thoughts on Would a special keyword for the accessing the current value in the cascade, similar to So instead of this .selector {
filter: grayscale(50%) !add;
} How about .selector {
filter: grayscale(calc(currentValue) + 50%);
filter: grayscale(calc(currentValue) - 25%);
filter: grayscale(calc(currentValue) / 2);
} Then people can just run whatever operations the value/type that was already in the cascade? Would currentValue need some sort of fallback if it was previously set to a different type? Like |
This looks similar to the What you could do though is rely on a custom property to do the math, like this:
[1] https://lists.w3.org/Archives/Public/www-style/2013Apr/0711.html (coined |
I like having a way to read the inherited value of the same property for its flexibility as shown above! |
@FremyCompany I was thinking the |
Since custom properties cannot be set with references to their own inherited value, except in quite round about ways... <style>
body {
--mag: 0em; /* initial value */
--plus: 1em;
--current: var(--mag);
}
span {
--current: calc(var(--mag) + var(--plus));
}
div {
--mag: var(--current);
property: var(--current);
}
</style>
<body>
<div>
<span>
<div>
<span>
<div>
<span>
<div>
</div>
</span>
</div>
</span>
</div>
</span>
</div>
</body> I hope whatever solution is found for "additive" does away with this mess, since we are missing things like shorthand assignment operators ( |
I had to write something like this today, overspecifying and repeating myself, explicitly accounting for all possible permutations of combined counter incrementing utilities. .ut-count-1 { counter-increment: utCount1; }
.ut-count-2 { counter-increment: utCount2; }
.ut-count-3 { counter-increment: utCount3; }
.ut-count-1.ut-count-2 { counter-increment: utCount1 utCount2; }
.ut-count-1.ut-count-3 { counter-increment: utCount1 utCount3; }
.ut-count-2.ut-count-3 { counter-increment: utCount2 utCount3; }
.ut-count-1.ut-count-2.ut-count-3 { counter-increment: utCount1 utCount2 utCount3; } <li class="ut-count-1"></li>
<li class="ut-count-1 ut-count-2"></li>
<li class="ut-count-1 ut-count-2 ut-count-3"></li>
... |
Re: variables, letting |
Related to this conversation is the ability to cascade |
If additive behaviour was defined on a per-property basis it could apply even where lists of items aren't natural - for example: <style>
.disabled {
text-decoration: line-through !add;
}
a {
text-decoration: underline !add;
}
</style>
<a class="disabled">underlined and struck-out</a> or, slightly more hypothetically: <style>
p {
text-spacing: trim-adjacent-to-punctuation; /* a made-up value */
}
:lang(fr) {
text-spacing: punctuation !add;
}
</style>
/* Remove spacing around the colon AND insert a 1/4 nbsp before */
<p lang="fr">Punctuation : le colon</p> Various forms of text "fix up" keep being proposed[1][2][3][4][5][6], and additive behaviour seems like a good option for what will inevitably become an increasingly long list. For font-feature-settings too. Here, I was wondering how you might offer more control over the cascade than just "add to, rather than replace, the previous matched value" p {
font-feature-settings: "ss01" !name swash;
}
.fancy {
font-feature-settings: "ss02" !add; /* gets "ss01", "ss02" */
}
.noswash {
font-feature-settings: inherit !remove swash; /* gets "ss02" */
} This would require each declaration has a name field, but beyond that should be no harder than the vanilla "!add" proposal. [1] https://www.w3.org/TR/css-text-4/#text-spacing-property |
Hello there, I am just a humble web dev, nothing important, but I stumbled upon your discussion and I woul like to add my views. So instead of:
For animations I have also bee thinking about compounding a CSS var: :root {
--animation: ;
}
.animated {
animation: var(--animation);
}
.slide-in {
--animation: slidein 5s;
}
.colour {
--animation: var(--animation), colour 5s;
} See my pen - I have commented out the compound var expression so that the pen will work. Whatcha think? :-) |
I'm gonna read all of this @LukeTOBrien thanks for informing the AnimateCSS community. |
building an animation grudgingly in javascript, just for additive compositing. wish I could use CSS only. here to say I would have reached for it right now if I could 👍🏻 |
This would be useful for any CSS property that accepts layers, like A way to add to these, or even compose them, rather than fully overwriting them, would be great. |
I think you added this comment to the wrong issue? |
+1, this would be really useful for design systems that need to define specific properties without overriding user styles. |
It's not clear to me (particularly given #1594 (comment)) whether this issue should cover all additive cascading concepts in CSS, or only those intended for animation. Also, for what it's worth, the earliest additive cascade proposal that I could find is https://lists.w3.org/Archives/Public/www-style/1999Oct/0025.html . |
You can consider the syntax with a plus sign "+" at the very end . button{
transition: width 0.5s;
transition: box-shadow 0.5s +;
transition: background-color 1s +;
} Optionally, you can consider specifying the order of the member after the plus sign "+" button{
transition: width 0.5s;
transition: background-color 1s +2;
transition: box-shadow 0.5s +1;
} This is the equivalent of button{
transition: width 0.5s, box-shadow 0.5s, background-color 1s;
} The description should apply to all multilayer properties. Such as :filter, background, transition, box-shadow, text-shadow and ... This will allow you to structure styles by meaning. button{
/* Transition Width */
width: 50px;
transition: width 0.5s;
/* Transition box-shadow */
box-shadow: 0 0 10px black;
transition: box-shadow 0.5s +;
/* Transition background-color */
background-color: red;
transition: background-color 1s +;
} |
I believe those for animation are already covered by the prior resolution to ship Web Animations with additive animation and by the And given the long discussion in this issue about a general solution, I think it makes sense to keep using this issue to find a general solution. @tabatkins Could you explain why you think @Kilian's comment belongs to a different issue? Regarding "all cascading concepts", we should first clarify what those different concepts are. As far as I can see, we have two general main concepts (which @birtles already mentioned in his initial post). Manipulating a numeric inherited valueThis means a numeric value is calculated relative to the value given by the cascade. In Brian's example this was a I guess those use cases may already be covered by #2864, Adding a value to a list of valuesThis means any kind of value is appended to (or removed from) the list of a property's value, independent of whether it is inherited or not. This is what Brian wrote as As mentioned above, there might also be cases in which people want to remove a value from the list of values. E.g. as we now have style containment by default (which can't be removed at the moment), people may explicitly remove it for cases they only want size containment to improve performance. Sebastian |
Additive CSS
The following material has been prepared for discussion at the August 2017 CSS F2F in Paris, France.
Outline
The goal of this discussion is to:
Part 1: Additive animation
This section describes what additive animation is, how it works, and why it is part of Web Animations.
What is additive animation?
Typically when two independent animations target the same property on the same element, one animation will clobber the other.
This can be either because of the nature of the CSS cascade, e.g.
(Demo)
Or simply because only one animation is ever applied to a given property, e.g.
(Demo)
Additive animation, however, allows the two independent animations to be combined together.
For example, using the Web Animations API we can express the above as:
(Demo - requires Firefox Nightly or Chrome Canary)
CSS Animations 2 proposes to expose this using the
animation-composite
property.e.g.
How does it work?
Firstly, animations that target the same property are arranged in order. This order is important because:
Web animations defines this as an effect stack. For animations created using the API the order is roughly equal to the order in which the animations are generated but for CSS animations, it is based on the order of the animations listed in the
animation-name
property.At the bottom of the stack is the unanimated value, called the underlying value. It is possible for a single animation to be combined with the unanimated value using this same mechanism, e.g.
(Demo - requires Firefox Nightly or Chrome Canary)
The specific procedures for adding each property needs to be defined just as we define the specific procedures for interpolating each property. The intention is that both the interpolation procedures and addition procedures for common types will be defined in CSS Values and Units and then specifications
that define new property types can defined further procedures.
One technical detail is that in some cases there are multiple notions of addition. For example, for a filter list we can define
blur(2px) + blur(5px)
as eitherblur(2px) blur(5px)
orblur(7px)
.As it turns out SVG uses both these modes. When two independent animations are added together it does list concatenation, i.e.
blur(2px) blur(5px)
from above. When an animation is defined to build on itself on each iteration it adds the function components, i.e.blur(7px)
from above.(Technically SVG only makes this distinction for transform animations and it doesn't actually do list concatenation, but matrix post-multiplication which is functionally equivalent.)
Web Animations calls these two modes
add
andaccumulate
respectively, and collectively calls these composite operations.Why does Web Animations have additive animation?
The original brief for Web Animations was that it should represent the common base for CSS Animations, CSS Transitions, and SMIL/SVG animation. SMIL/SVG animation has additive animation so therefore Web Animations has additive animation.
Is it needed?
The most common usage of additive animation is for combining transform animations. A number of these use cases can be addressed using the individual transform properties from CSS Transforms 2. However, this does not cover all use cases such as:
filter
(e.g. animating the blur on an element that already has a sepia effect applied), or evenopacity
(e.g. animating the opacity to +50% of its current value).The other alternative to additive animation is to simply add more and more
<div>
elements to represent each possible independently timed animation component. This approach does not scale well to dynamic animations where a potentially unbounded number of animations might be generated dynamically and having to adding elements for this is, in this author's opinion, one of the more frustrating parts of authoring CSS at the moment.Part 2: Static CSS and addition
As it turns out, the notion of combining CSS property values is useful beyond just animations.
Use cases
e.g. truly generic classes
e.g. modifying underlying values
e.g. combining animations defined by different rules that target the same property
e.g. overriding certain list items by using the cascade order
Proposal:
!add
annotationI believe both David Baron and Tab Atkins have at some point considered the idea of an
!add
annotation for this.For static CSS the CSS cascade (that is selector specificity etc.) provides the ordering for composition. The absence of an
!add
annotation on a declaration indicates that any lower priority declarations are ignored as they are today (even if those lower priority declarations have!add
annotations).Issues that need consideration
Some issues that would need to be considered as part of such a proposal:
!add
enough? Do we need both theadd
andaccumulate
modes described above?calc()
to be able to work with the underlying value?!add
annotation is in place so that is is possible to writeopacity: -50% !add
?(We already do this internally for SMIL and I suppose we want to do this for
animation-composite
anyway.)Part 3: Shipping additive animations
The purpose of raising this proposal is to consider the implications of shipping additive animations now and later introducing a more generalized mechanism.
How would the additive features specified in part 1 change if we also eventually do part 2?
Example 1: Setting the composite mode in a single keyframe
Example 2: Setting the composite mode across all keyframes
I think these same principles could equally apply to the CSS syntax if we choose to ship that too. For example, taking Example 1 and translating it into the proposed CSS syntax from CSS Animations 2:
It seems to me that there is a relatively straightforward path for harmonizing the approach in part 1 if we also do part 2 and that, in fact, the features introduced in part 1 might be useful in combination with part 2 as a way of bulk-setting the composite operation.
The text was updated successfully, but these errors were encountered: