- From: Dean Jackson <dino@apple.com>
- Date: Wed, 10 Sep 2014 08:58:02 +1000
- To: "<www-style@w3.org>" <www-style@w3.org>
NOTE: This isn't a very polished proposal. Since it is www-style I'd expect a zillion comments/alternatives/complaints even if it were polished. This is a proposal for three new CSS animation properties in Level 2 of the specification. - The first, animation-trigger, determines the moment which an animation will consider its clock/timebase to begin and end advancing. The best example of this is an animation that should trigger when the page has been scrolled to a particular point. - The second, animation-timebase, specifies what the animation should use as a clock. By default it is wall-clock time, but this property would allow the animation to map the scroll position of a page into the animation's time domain (effectively scrubbing the animation as the user scrolls), or possibly use a media element as the clock. - The third, animation-behavior, specifies if concurrent animations on the same property should overwrite or add to the value (as defined by 4.1.3 of Web Animations) We've made a prototype implementation of these features and are very happy with the results. Not only were we able to replicate many of the currently common trends in Web design (pages that react to scrolling), we were able to do so in a purely declarative manner. So-called "parallax" effects are easy to design with this feature. There is also a performance benefit. With this feature it is possible to determine in advance if a scroll will trigger layout, which allows an implementation to optimize the scroll (e.g. if scrolling and animation happen on a separate thread). The implementation itself was also quite simple. We wouldn't expect it to be a burden for other browser engines. But, most importantly, it provides a significant increase in functionality for CSS animations, while being a very small addition to the specification. It also fits in nicely with the Web Animation model, effectively providing some declarative syntax for what WebAnim exposes in script. Now, for the more formal version. We're not particularly concerned with syntax at the moment, so I expect many comments and the names to change over time. animation-trigger ----------------- Name: animation-trigger Value: auto | scroll(<snap point> [, <snap point>]+) Initial: auto Inherited: no Animatable: no Defines the point at which the time input to the animation will "tick", effectively controlling when the start time of the animation will be, and when the animation clock will stop advancing. A value of "auto" means the animation will use its timebase as a trigger (which is the wall-clock time by default). This is the current behaviour, where an animation will start at a time determined by animation-delay after the moment the animation style was applied. A value of "scroll" means the animation will begin advancing its time value/timeline once the element's scrolling container has scrolled to a particular position. It uses the same syntax as CSS Scroll Snap Points, although we might need to tweak the syntax a bit because I think people will want expressions like calc(elements + 10%), so the animation starts slightly before the element comes onto the page (see NOTE1 below). The scroll function takes a list of values. The odd values define starting triggers. The even values define a corresponding ending trigger. An ending trigger simply freezes the timeline once it is hit (although see the animation-timebase property below). Each trigger fires once as the container scrolls from above the point to below the point (See NOTE3). NOTE1: Just the scroll snap point is not enough. We also need the scroll-snap-coordinate and scroll-snap-destination. It's a shame there is no shorthand for the scroll snaps. NOTE2: there are so many ways to define the syntax here that we expect it to change a lot. The important features are: - starting an animation at a point in the page - a point is able to be specified in relation to an element's position - it's possible to specify an end point, which would stop the animation (although this could be split into two properties, so you could have on/off animations as you scroll). NOTE3: We'll probably need something to define if the trigger should refire if you scroll past the point again. NOTE4: Should there be a way to have something inside overflow:scroll react to the page's scroll? (without crossing frame boundaries) Example 1. Fade elements in when they are scrolled into view. .reveal-section { animation-name: fade-in; animation-duration: 1s; animation-fill-mode: backwards; animation-trigger: scroll(elements); } @keyframes fade-in { from { opacity: 0; } to { opacity: 1; } } Example 2. Spin an element while the page is between two points, assuming the element is not inside a child scrolling container. .spins-on-position { animation-name: spin; animation-duration: 300ms; animation-fill-mode: both; animation-iteration-count: infinite; animation-timing-function: linear; animation-trigger: scroll(100px, 500px); } @keyframes spin { from { transform: rotate(0); } to { transform: rotate(1turn); } } NOTE: The syntax is designed to be extensible, so that future triggers could be easily added. For example: - some point in a media stream - after a resource load - before page navigation - after another animation ends or iterates animation-timebase ----------------- Name: animation-timebase Value: auto | scroll | url(<media element>) Initial: auto Inherited: no Animatable: no The animation-timebase property defines how the time value will advance. The default value is "auto", which means the animation uses the normal document timeline (as it does today). A value of "scroll" means the timeline of the animation will be driven from the scrolling container's position. This works in conjunction with the animation-trigger, such that the duration of the animation is mapped onto the length of the trigger. In Example 2 above, 100px would be equivalent to 0s and 500px would be equivalent to 300ms, meaning the animation would play through once as you scrolled. Obviously scrolling up the page would effectively reverse the time. If the animation does not have an end trigger, "scroll" acts like "auto" (or should there be a defined end? My example below uses the end of the page as the end trigger.). A value of "url()" references a media element that acts as the timebase. The duration of the media maps to the duration of the animation. NOTE: There should be a way to map the duration *range* of the media to the duration of the animation, so that you don't need to know the media duration in order to make a progress bar. Example 3. Draw a reading progress bar along the top of the page as the user scrolls. #progress { position: fixed; top: 0; width: 0; height: 2px; background-color: red; animation-name: progress; animation-duration: 1s; animation-timing-function: linear; animation-trigger: scroll(0px); animation-timebase: scroll; } @keyframes progress { from { width: 0vw; } to { width: 100vw; } } animation-behavior ----------------- Name: animation-behavior Value: replace | add Initial: replace Inherited: no Animatable: no Defines how multiple animations on the same property interact with each other. The default value is "replace", where the last animation will overwrite all other animations in definition order. A value of "additive" means that the animation will add to the value provided by the previous animation. This term, and how it works on various properties like transform and color, is defined in lots of other specs. For example, section 4.1.3 of the Web Animations spec lists a lot of cases (color, transforms, lengths). Example 4. Animate translation and rotation separately. #woohoo { animation-name: move, spin; animation-duration: 3s, 7s; animation-iteration-count: infinite; animation-direction: alternate; animation-behaviour: replace, add; } @keyframes move { from { -webkit-transform: translate(0); } to { -webkit-transform: translate(500px, 500px); } } @keyframes spin { from { -webkit-transform: rotate(0); } to { -webkit-transform: rotate(2turn); } }
Received on Tuesday, 9 September 2014 22:58:35 UTC