- From: Tab Atkins Jr. <jackalmage@gmail.com>
- Date: Mon, 5 Apr 2010 10:39:13 -0700
- To: Håkon Wium Lie <howcome@opera.com>
- Cc: Anne van Kesteren <annevk@opera.com>, www-style@w3.org
On Mon, Apr 5, 2010 at 8:20 AM, Håkon Wium Lie <howcome@opera.com> wrote: > .button { > color: blue; > } > > .button:hover { > color: red; > effect: on-entry change(color, 1s), on-exit change(color, 1s); > } > > .button:focus { > color: green; > effect: on-entry change(color, 1s), on-exit change(color, 1s); > } > > So, the button will start off being blue. Let's say the element first > is hovered (and turns red), and then is focused (and turns green). > This is given by the normal cascading rules in CSS. That's a lot of repetition, and it still doesn't cover all cases (.button[disabled] turning color:gray?). All I want to have to do is say "Hey, you, button. Always transition your color.". Your proposal would require me to specify an on-entry and on-exit for *every single state* that changes the color of the button. Transitions handle that use-case with a single simple property on ".button". This is the sort of regression we were afraid of seeing during the FtF discussion. I don't think you can go about this task piecemeal. If you really want to integrate animations and transitions, you'll have to do so by reexamining the core use-cases, and finding an abstraction that fits them all. I believe there are 3 primary cases we're trying to hit: 1. Upon a *property value* changing on an element, do something to that element (possibly just animate that property, possibly animate other properties) 2. Upon an element changing *state* (defined implicitly by a selector), do something. 3. While an element is *in* a state, do something. Right now, Transitions addresses part of #1 (animating the property that changed only), Animations addresses #3 (infinite animations) and part of #2 (you can only really control what happens when you enter a state, not leave it), and you can sort of hack them together to fully address #1. I think that, fundamentally, #1 and #3 require different mechanisms. The concept of "property" and "state" are completely separate in CSS. I don't think we can really tie these two things together in a useful way. There are some places where we can change things, though. We should be able to fully address #1 without relying on difficult hacks (anything requiring :not(:hover) as a basic mechanism is screwed up ^_^). We should also be able to fully address #2. I actually think we may be able to do this by making Transitions and Animations slightly *more* different. Here's a sketch of how they would work: /* In this example, the transition-property value (and its place in the shorthand) also take a function defining a set of keyframes to execute when a given property transitions. */ .slider { left: 0; transition: left 1s, play(left, bounce) 1s; } .slider:hover { left: 400px; } /* In this example, there is an animation run when you enter a state, while you are in the state (delayed by 1s, so as to wait until all transitions and play-ins are done), and when you leave the state. Also some transitions for good measure. */ .tooltip { opacity: 0; display: none; transition: opacity 1s, display 1s step-start; } .tooltip.show { opacity: 100%; display: block; play-in: rainbow 1s; play-during: throb 5s 1s; play-out: rainbow reverse 1s; } The changes are relatively minor here: 1. Transition-property takes another value, which specifies a (property, keyframe) pair. 2. Three new shorthand properties: play-in, play-during, and play-out. Play-in specifies animations to be run when the element begins to match the given selector. Play-out plays when the element stops matching. Play-during plays infinitely while the element matches. 2. "infinite" is no longer a possible animation duration. Instead, all keyframes given for the play-during property are assumed to run infinitely (and play-during doesn't accept an animation-play-count), and all keyframes given for the play-in and play-out properties are assumed to be finite. Play-during simply doesn't *have* a play-count entry. 3. Any place that accepts a keyframe must also accept a keyframe followed by the 'reverse' keyword, indicating that the keyframes should be run backwards. 4. The operation of (and likely names of) the individual animation properties will have to be tweaked somewhat. Rather than a single "animation" shorthand with "animation-*" subproperties, you'll have three shorthands and three separate groups of subproperties (play-in-name, play-during-delay, etc.). What's left to define: 1. How a keyframe set takes default values when played in a transition. Obviously 100% should default to the end-state. What about times in the middle? Basically, I'd like to be able to *either* do a simple transition taking a property (say, left) from value A to value B, or do a complex transition using keyframes to take the property from value A to value B with a complex path in between. I'm not sure what's ideal here yet. 2. How a keyframe-based transition and a standard transition interact on the same element. We may want to say that they *can't* interact, and that transitioning both "left" and "play(left, bounce)" brings the same conflicts that transitioning "left" twice does, and so we resolve them in the same way (last one specified wins). This would mean that in my first example I'd have to remove the "left 1s" bit and specify what to do with "left" in the bounce keyframes. Alternately, since you can statically examine keyframes and see what properties are manipulated by one, perhaps just say that if a keyframe manipulates a property, it overrides any manipulation that would be done by earlier keyframes or transitions. This is likely better, as it handles being able to hook multiple keyframes to the same property elegantly, and also fits with the idea that a plain transition is an instantaneously-produced trivial keyframe. 3. How animations of the various types (in, out, during) interact with eachother. Does during always beat in? Out beat during? What about when you fill any of these? I think this can be resolved fairly easily, if perhaps arbitrarily. A final use-case that hasn't been addressed is "one-shot" animations, which are useful for javascript. Say you want to throb a button every time someone clicks on it. This is an animation not tied to a state or a property value change, but rather to an action or event originating from elsewhere. These would basically just be triggered by javascript. My initial thought is to just do them as a normal animation tied to a class, and in js just quickly add and remove the class that triggers it. This doesn't work, though, as removing an animation (or equivalently, making an element no longer match a selector providing an animation) stops the animation (I think?). Can I just listen for the animationend event and remove the class then? This doesn't help me if I want to restart a running animation if the user clicks again, though. Being able to directly trigger an animation through JS would be somewhat useful for this sort of thing. I suppose this can wait a bit, though. So, I think this sort of approach, slightly further differentiating transitions and animations, would actually help a lot more, and seems to make a lot of the expected common use-cases very simple. ~TJ
Received on Monday, 5 April 2010 17:40:02 UTC