Talk:F2F/Auckland 2011/CSS Animation

From SVG
Revision as of 01:29, 14 March 2011 by Cmccorma (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

I am putting some additional notes that I have made on the topic here, in the hope of integrating them with the CSS Animation page. --heycam 23:49, 20 February 2011 (UTC)

Using CSS Transitions/Animations with current SVG attributes

If we agree that targeting what are currently attributes in SVG (such as geometry attributes of graphics elements) is useful, then there are a couple of ways we could go about it.

Promoting attributes to properties

One way is to change the SVG language such that these attributes now are actually properties. This would allow CSS Transitions/Animations to be used without any modification. For example:

<style>
  circle {
    r: 100px;
    transition: r 0.5s;
  }
  circle:hover {
    r: 110px;
  }
</style>
<circle cx="100" cy="100"/>

This is good for authors in that they can simply use CSS Transitions/Animations as they have learned, and apply their knowledge directly to transitioning/animating anything currently defined as an animatable attribute.

Here are some issues.

CSS has existing properties for defining the extent of CSS boxes: top, left, width, height. An SVG rect has x, y, width, height. Do top and left have any significance? It may be confusing to use different properties.

  • But other elements such as circle would need completely different properties anyway, so I think this argument is not very strong.

Currently in SVG, we have slightly different rules as to what is allowed in presentation attributes compared to in a style sheet. This is what results in scientific notation being allowed in, say, the 'stroke-width' presentation attribute but disallowed when stroke-width is specified in the 'style' attribute. We would need to be mindful that the syntax for attributes we promote fits in with the CSS parser.

  • This likely isn't a problem, actually. For scientific notation and similar, we could just keep rules about the different parsing of presentation attributes versus property values in style sheets. For syntax fitting in with the grammar, I haven't noticed any values yet which would cause problems.

It changes the current distinction drawn between attributes and properties in the language. In HTML, the division of HTML attributes and CSS properties is the semantics/styling one. Styling is (meant to be) optional for understanding the document. In SVG, I think of CSS support as more fundamental to the semantics of the document: that a shape has a particular size or dimension is probably semantically important, but also its colour will be. That might not have been the view of the original authors of the SVG specification, I’m not sure.

  • On the other hand, sometimes the geometry of an element may not need to be a particular value to convey the semantics of the document – instead it might just be a visual effect for aesthetics. However, it is not possible to affect the geometry of an element in CSS, and the only way to do that is to set attributes on the element itself. So it is currently not always possible to correctly divide semantics and style between the XML and CSS anyway. (I am imagining presentation attributes as being part of encoding the semantics of the document, here.) Thus I think you can argue that, if maintaining this distinction between semantics and styling is useful, promoting some attributes to properties gives more flexibility to the author to declare which aspects of a document are semantically important and which are stylistic choices.

Currently in SVG, properties are never exposed with SVG DOM interfaces (such as SVGAnimatedLength properties on the element). If SVG attributes were promoted to properties, we would need to decide whether to break with this rule, and to expose the property through the SVG DOM.

  • We need to come up with better ways of exposing information than the current SVG DOM interfaces anyway, so even if we make some choices here to maintain backwards compatibility while breaking consistency, we shouldn't mind much because we might want to deprecate these interfaces.

Do we choose a set of attributes to promote to properties, and if so, what is that set? The set of animatable SVG attributes would be a good starting point. (Patrick lists an initial set of attributes on the main wiki page.)

In CSS, properties have global meaning/syntax across elements. SVG attributes can have different meanings. For example x on text takes a list of lengths, while it takes only a single value on rect. Convincing the CSS WG that there should exist a global property named “x” would be very difficult, I imagine!

  • This is probably the strongest argument against directly promoting attributes.

Introducing new properties

If we wanted properties for the geometry and other animatable SVG attributes, then instead of creating properties with the same names as these attributes, we could introduce properties with different names. This could avoid the issues with CSS properties being in a global namespace, where "x" would be considered much too general to introduce solely for a few SVG elements' use.

For example:

<style>                                                                                                                                                    
  circle {                                                                                                                                                 
    circle-radius: 100px;                                                                                                                                  
    transition-property: circle-radius;                                                                                                                    
    transition-duration: 0.5s;                                                                                                                             
  }                                                                                                                                                        
  circle:hover {                                                                                                                                           
    circle-radius: 110px;                                                                                                                                  
  }                                                                                                                                                        
</style>                                                                                                                                                   
<circle cx="100" cy="100"/>                                                                                                                                

We would then have two choices about what to do with the presentation attributes:

  • add a corresponding circle-radius presentation attribute, so that <circle circle-radius="100"/> works, define how r="" and circle-radius values compete to result in the circle's radius, and leave r="" as a plain attribute; or
  • just make r="" be the presentation attribute corresponding to circle-radius.

The latter breaks the current naming correspondence between properties and presentation attributes. The former means that there are now two attributes you can put on <circle> to set its radius, which could be confusing.

Allowing CSS Transitions/Animations to target attributes directly

If creating properties for these attributes is unpalatable, we can consider allowing CSS Transitions/Animations to be able to target attributes directly. Say you want to transition the x position of a rectangle and to animate the y position. A first try at defining this would be to allow something like the following:

<style>                                                                                                                                                    
  rect { transition: x 0.5s; animation: a 0.5s both infinite }                                                                                             
  rect:hover { x: 110px }                                                                                                                                  
                                                                                                                                                           
  @keyframes a {                                                                                                                                           
    from { y: 100px }                                                                                                                                      
    to { y: 110px }                                                                                                                                        
  }                                                                                                                                                        
</style>                                                                                                                                                   
<rect x="100" y="100"/>                                                                                                                                    

But this has a couple of problems:

  • x might be the name of a property the CSS WG wants to introduce in the future (we're stepping on the namespace of property names with something that's not a property).
  • For transitions, the rule set is just a normal CSS property rule set, so x isn't even the name of a property here; changing regular CSS rule sets to allow non-properties would be difficult/impossible.
  • For the declarations inside @keyframes, it would be slightly more acceptable to extend them to allow attributes names like the above, but it would introduce a divergence between regular rule sets and those appearing in @keyframes, which would cause author confusion.

You could get around these problems like so:

<style>                                                                                                                                                    
  rect { transition: attribute x 0.5s; animation: a 0.5s both infinite }                                                                                   
  rect:hover { transition-attribute-values: x 110px }                                                                                                      
                                                                                                                                                           
  @keyframes a {                                                                                                                                           
    from { animation-attribute-values: y 100px }                                                                                                           
    to   { animation-attribute-values: y 110px }                                                                                                           
  }                                                                                                                                                        
</style>                                                                                                                                                   
<rect x="100" y="100"/>                                                                                                                                    

This "plays nice" with CSS, but is a bit clunky compared to animating/transitioning properties, and also isn’t combinable – if you put all attribute animation/transition values into a single property, you can’t draw in different attribute/value pairs from different rule sets. (This is a problem that affects the transition-property property anyway, though!)

Inside @keyframes, we are at liberty to introduce a bit of new syntax:

<style>                                                                                                                                                    
  rect { animation: a 0.5s both infinite }                                                                                                                 
                                                                                                                                                           
  @keyframes a {                                                                                                                                           
    from { fill: red }                                                                                                                                     
    attributes from { y: 100px }                                                                                                                           
    to   { fill: gold }                                                                                                                                    
    attributes to { y: 110px }                                                                                                                             
  }                                                                                                                                                        
</style>                                                                                                                                                   
<rect x="100" y="100"/>                                                                                                                                    

And I guess we could do that for transitions too:

<style>                                                                                                                                                    
  rect { transition: attribute x 0.5s; animation: a 0.5s both infinite }                                                                                   
  @attributes {                                                                                                                                            
    rect:hover { x: 110px }                                                                                                                                
  }                                                                                                                                                        
                                                                                                                                                           
  @keyframes a {                                                                                                                                           
    from { fill: red }                                                                                                                                     
    attributes from { y: 100px }                                                                                                                           
    to   { fill: gold }                                                                                                                                    
    attributes to { y: 110px }                                                                                                                             
  }                                                                                                                                                        
</style>                                                                                                                                                   
<rect x="100" y="100"/>                                                                                                                                    

A bit yuk, but doable.

Another thing that would need to be defined is when a transition on an attribute is intitiated. For CSS, it is something like any change to the property's computed value, unless it is due to a declarative animation. For SVG, this could be changing the value of the DOM attribute itself, or modifying it via the SVG DOM.

Conclusions

Of these three possibilities, the one I dislike the least is the introduction of differently named properties (option #2).

At the SVG WG F2F, the choice that almost everyone else seemed to prefer is option #3, but with a slightly different syntax. With this option, transitions couldn't be triggered by CSS, only by DOM changes. Animations would work declaratively, though.

This wouldn't work:

<style>
  rect { transition: attr(x) 0.5s }
  rect:hover { attr(x): 110px }
</style>
<rect width="100" height="100"/>

because you couldn't have attr(x) on the left hand side of a regular CSS rule. This would work, though:

<style>
  rect { transition: attr(x) 0.5s }
</style>
<rect width="100" height="100"
  onmouseover="this.setAttribute('x', '110')"
  onmouseout="this.setAttribute('x', '100')"/>

which could use the heuristics that CSS Transitions defines for determining whether to automatically reverse a transition or to consider a value change like a new transition.

For animations, you would be allowed to use attr(x) on the left hand side of the rule inside the @keyframes rule. So:

<style>
  rect { animation: a 0.5s both infinite }

  @keyframes a {
    from { fill: red; attr(y): 100px }
    to   { fill: gold; attr(y): 110px }
  }
</style>
<rect x="100" y="100"/>

As mentioned earlier, Patrick suggests starting with a subset of animatable SVG attributes that can be targeted with CSS Animations. This subset is limited to types where we don't need to invent new CSS syntax for values, and where it is clear how the interpolation should be performed.

Timing functions

Timing is done slightly differently. In SVG, the timing function (specified with calcMode, keyTimes and keySplines) applies to the animation as a whole – over the entire list of values. In CSS, the timing function applies (and can be specified differently) for each pair of adjacent values (specified in the keyframes). This is why SVG's keySplines takes one or more sets of four cubic Bézier control points, while the CSS transition-timing-function and animation-timing-function properties take only a single set (with the cubic-bezier() value) per property being animated.

CSS Transitions/Animations allow more timing functions than SVG Animations. It would be good to allow authors to use these in SVG Animations:

  • linear
    This is just like calcMode="linear".
  • ease, ease-in, ease-out, ease-in-out, step-start, step-end
    These are predefined Bézier curves, and step-start is like calcMode="discrete". Should we allow these keywords as keySplines values?
  • steps(<number>[, start | end])
    This is similar to calcMode="discrete", but with more flexibility. You can specify more than one step, as opposed to the 1-or-2 steps that calcMode="discrete" will cause. You can also control whether the step happens at the start or end of the interpolation between the start and end value. These again could be keySplines values.
  • cubic-bezier(<number>, <number>, <number>, <number>)
    This is just like calcMode="spline" with keySplines specified.

So we might want to allow all of these values to be specified in keySplines lists. calcMode="spline" and keySplines seems the closest analogue to animation-timing-function.

Delaying

The transition-delay and animation-delay properties can be used to specify a fixed time to wait after the CSS transition/animation becomes active before the actual value interpolation begins. In SVG you can use begin timing specifiers with offsets to achieve the same effect, unless you need animation-fill-mode:backwards behavior.

Automatic reversal

CSS Transitions automatically reverse if the property is set to the starting value mid-way through the transitions. CSS Animations don't have this ability, and CSS Animations are closer to SVG Animations anyway. So do we need the ability to reverse SVG animations? It is something you can't currently do. For example you might have:

<rect width="10" height="10">
  <animate attributeName="fill" from="black" to="gold" dur="0.5s" begin="mouseover" fill="freeze"/>
  <animate attributeName="fill" from="gold" to="black" dur="0.5s" begin="mouseout" fill="freeze"/>
</rect>

and this exactly the kind of animation where with CSS Transitions, you get the better behavior by automatically reversing the timing. Since in SVG Animations the two directions need to be explicitly added as two separate animations, you don't really think of "reversing" one of them.

Unifying interpolation

We should ensure that interpolation of datatypes is defined the same for CSS Transitions/Animations and SVG Animations. Also I would prefer it if all CSS properties were animatable, with definitions about how to deal with values that cannot be interpolated (i.e., make them animate discretely between values).

Should CSS Transitions/Animations use the color-interpolation property to control in which space the interpolation is done, like SVG Animations?

There is a note in CSS Transitions about whether to interpolate premultiplied color components or non-premultiplied ones. Which makes sense? This should be the same between SVG and CSS. (This would apply to rgba values, which we technically don't have at the moment.)

Events

For CSS Transitions, a single "transitionend" event of type TransitionEvent is dispatched when a transition reaches its endpoint. Properties are:

  • DOMString propertyName
  • float elapsedTime

For CSS Animations, you have "animationstart", "animationend" and "animationiteration" of type AnimationEvent, for the start, end and repeat of an animation. Properties are:

  • DOMString animationName
  • float elapsedTime

For SVG Animations, you have "beginEvent", "endEvent" and "repeatEvent" of type TimeEvent. Properties are:

  • AbstractView view
  • long detail (contains repeat iteration)

It would be nice if we could use the same event types and interface for CSS and SVG Animations, at least. SVG Animations don't have names (although they could, for animation reuse). I am not sure what use cases elapsedTime have in particular, but it is no problem to have SVG Animation events have such a property. detail is a bad name for storing the repeat count (just as it is unintuitive for storing the click count in mouse events). It should be repeatCount or something similar. If there is a use case for it, then CSS Animation events should have it too.

I don't think it is particularly useful to have the view property on there; we seem to be acknowledging that there really is only ever a single view of a document these days, so it could easily be dropped without a problem. (You can get to the Window object through Event.target, anyway.)

Named animations

One of the major differences between CSS and SVG Animations is that in CSS, you define a set of keyframes with property values, give that set of keyframes a name, and then reference it from the animation-name property to make the animation apply. Thus you can easily re-use a set of animated values and key times for animating different elements. Some aspects of the animation are not reusable by defining them as part of the keyframes, for example animation-delay and animation-fill-mode. You can get some re-use of these just by virtue of them being CSS properties, and having multiple selectors listed for the ruleset that defines these properties.

In SVG you have no re-use of animations currently. We could allow SVG animations to be named and allow them to be referenced from a CSS property. For example:

<style>
  .glow {
    animation-name: glow;
  }
</style>
<animate name="glow" attributeName="fill" values="#88f; #fff; #88f" begin="click" dur="0.5s" repeatCount="3"/>
<rect width="10" height="10"/>

So an animate element with a name wouldn't implicitly apply to its parent. The key thing here that isn't currently supported by CSS Animations is the mousedown/mouseup. Basically with CSS Animations you can't write the kinds of complex start and end times that you can with SVG Animations.

One downside to reusing this CSS Animations way of applying an animation is that you run into the common CSS problem of this being a single property defining the whole set of animations to apply. You couldn't do:

<style>
  rect { animation-name: wobble }
  circle { animation-name: bounce }
  .glow { animation-name: glow }
</style>

and expect an element matching rect.glow to wobble and glow. This is a general problem that many CSS properties have, though.

How CSS Transitions and Animations and SVG Animations interact

SMIL requires that animation of CSS properties are effected by writing the animated values to the target element's override style sheet. No easy way is given to get access to the base value. CSS Transitions and Animations simply change the way the computed value of a property is determined, by taking animations into account – it is not done by writing to the override style sheet. Since the override style sheet is normally used in determining computed values, this would mean that CSS Transitions and Animations take precedence over SVG Animations of CSS properties.

For consistency with this, if SVG attributes could also be targeted by CSS Transitions/Animations, then they would take precedence over SVG animations of those attributes.

For example:

<style>
  rect {
    animation-name: a, b;
    animation-duration: 2s;
  }

  @keyframes a {
    from { fill: black; }
    to   { fill: green; }
  }

  @keyframes b {
    from { fill: black; }
    to   { fill: blue; }
  }
</style>
<rect width="10" height="10">
  <animate attributeName="fill" values="black; red" dur="2s"/>
</rect>

This would animate the rectangle from black to blue. The SVG animation would be on the bottom of the sandwich, the "a" animation in the middle, and the "b" animation on the top.

Currently, since CSS animations cannot be additive, it is not useful to have SVG animations below CSS animations. If an author wants to have SVG animations above CSS animations, then the SVG animations could be applied via the animation-name property instead of the (implied or explicit) xlink:href on the animation element. The order of animation names in that property would define the sandwich order.

Applying the CSS Animation properties to SVG Animations

If SVG Animations can be applied with the same CSS property you can use for CSS Animations as in the previous section, then we should see whether other CSS Animation properties should also work with SVG Animations:

  • animation-delay
    When an SVG Animation applies to an element that has a non-zero value of animation-delay, this would delay the effect of the animation by the given time. We don't want to think of this simply as adding this time as an offset to all of the begin/end timing specifiers, because we would want to make animation-fill-mode: backwards do something still. We could also make this property apply to the animation elements themselves, in order to allow different animations targeting the same element to have different delay amounts.
  • animation-direction
    This could easily work with SVG Animations. When animation-direction is set to alternate on an element that is the target of SVG Animations, then the animation effects just run backwards every second repetition. This property could also be set on the animation elements themselves.
  • animation-duration
    On an animation target, sets the simple duration of all SVG Animations that don't have a specified dur attribute. On an animation element, it also specifies the animation duration. (Perhaps the dur attribute could influence the computed value of animation-duration on the animation element, if it is not exactly the presentation attributes – users might expect the presentation attribute to be named animation-duration, actually.)
  • animation-fill-mode
    As with animation-duration, this property would set SVG Animation fill behavior when the fill attribute is not specified. The value "fill" could be a synonym for "forwards". (Aside: I don't think the "both" value is obvious enough as to what it means.)
  • animation-iteration-count
    Same. This would apply when repeatCount and repeatDur were not specified on the animation element. "infinite" and "indefinite" could be synonyms.
  • animation-play-state
    SVG Animations can't be paused individually, currently. No reason why this property couldn't apply to SVG Animations. As a presentation attribute name on an animation element, it might look out of place compared to the shorter names like "begin" or "fill".
  • animation-timing-function
    This could be used if calcMode/keyTimes/keySplines are not specified. (Would this be in addition to allowing the canned timing functions as calcModes?) When cubic-bezier() is specified, the equivalent keySplines would be a repetition of that single curve to match the number of values being animated, because animating-timing-function specifies the timing between two values, while keySplines specifies the timing between each pair of adjacent values.

Features in SVG Animation not in CSS Animation

  • motion animation
    This would be hard to achieve in CSS Animation just by animating left/top properties separately. Maybe CSS should gain functionality like this?
  • calcMode="paced"
    This is most useful with motion animation.
  • complex begin timing specifiers: syncbase, eventbase, repeat, accessKey, wallclock
    If CSS Animations wanted to allow animations to begin on UI events, a property animation-begin or so could be introduced, allowing values like "click" or "myDiv.mouseover".
  • end times
  • min/max
    I don't find these useful.
  • restart
  • "by" value
  • additive animations
    I think additive animations are useful and I think CSS Animations should be able to be additive.
  • cumulative animations
  • animateTransform
    I don't think anything special needs to be added to CSS to support this; transform is already a property there, and how transform lists interpolate is defined.
  • ElementTimeControl
    These allow SVG animations to be started/stopped with a method call. It is something, but a more comprehensive DOM interface to animations would be better. (I think dino said he was working on a proposal for this.)
  • SVGAnimationElement
    These allow querying animation elements for their start time, current time and duration. This information probably has some uses, and I think it should be exposed in a manner consistent with a proposed DOM interface for animations.