Ever since WebKit started to introduce all these fancy new CSS properties like 2D and 3D transformations, transitions and declarative animations I’ve been drooling like a script kiddie from the year 2000. I’ve been thinking about how I can use them in some Google property but unfortunately the whole world is not using nightly builds of WebKit so I’m pretty limited to just playing around at home. Well, platying around home is not
exactly what I did. Most of the time I was actually playing on the bus going home from work.
I’ve been playing around doing a KeyNote like animation done with CSS and some JS to hook up the necessary events. The animation is kind of like a deck of cards. When you go to the next one the current one zooms in and fades out,
symbolizing getting closer to the viewer. The next card then zooms and fades in from the back and to give a fancy effect
Example 1 (use left and right arrow keys to go between the cards.
I started off playing around with the @keyframes rule. This is the CSS animation that gives you most control and it should be good enough to be able to replace most of your js animations. I believe JS libraries should be able to use the CSS animation internally as long as no code depends on ” any animation” events except start and begin.
The CSS animation allows you to set the animation-name at the time you want to start your animation. You can set up multiple keypoints at different intervals but for the simplest case you only need to set the from (0%) and to (100%) frames.
For the animation I had in mind I needed 4 animations. fade-in-backwards, fade-out-backwards, fade-in-forwards and fade-out-forwards. These are extremely simple and I was very tempted to create these using the CSSOM but I never went that far.
To play the animation forward I set the animation-name of the current card to fade-out-forward and the next card to fade-in-forward (and the fade-*-backward for animation backwards).
The CSS animations has a few drawbacks. One of them is that when the animation is finished it is pretty cumbersome to freeze the state. One way to achieve the freezing is to listen to the window.onwebkitanimationend event , check the
animationName of the event, read the computed style and apply that. The problem with this is that I either iterate over all CSS properties used in the to (100%) keyframe or I manually keep track of the properties I want to freeze. I ended up
manually setting the properties because I was laze. This does not scale well of course so if you are serious about freezing your animations I would recommend writing functions to freeze the animation (you will need to be able to unfreeze
it if you want to animate it again).
I can think of two other drawbacks. One is mentioned in the spec proposal and that is the ability to pause the animation. The spec proposal currently supports this but they are considering removing it. If they remove it the user will have to write some non trivial js to freeze the state again (same thing as I talked about before). I’m not even sure how resuming would work since I don’t think there is a way to set the time for the animation.
It turned out that my use case is actually a transition (surprise) and for transitions, CSS transitions are much better suited.
Transitions allow you to change a CSS property (any property that supports transitions) and it will animate the property when changed. For example, if you say that “width” should be a transition-property, setting the width will animate the width from its old width to the new width. I cannot emphezise enough how useful this property is. Please reread this paragraph and makes sure you get it Now how many lines of js do you need to make your elements fade in and out when you show and hide them? None, it is easily done with one line of CSS (if
you use opacity to hide them that is).
So back to the KeyNote like demo. The idea here is to set all the coming cards to zoomed out and totally transparent and all the previous cards to zoomed in and transparent. Now you only need to change which element is current by setting the zoom to 100% and the opacity to 1. Done!
That is not entirely true, I also updated the class name of the previous and next card.
This is an iteration on the previous one. Instead of defining .next, .current and .previous classes I realized I could use the :target CSS selector in combination with the next sibling selector. The :target selector matches any
element with the same id as the hash fragment of the URL. This is mostly used for highlighing the target of an internal anchor that was clicked but it can be used for other more fancy things (like tab panes for example).
When the page loads I needed to ensure that the URL contained a hash fragment and if it didn’t I replaced the URL with one that did. Also, I needed to add some code to sync the current card with the hash, allowing the user to bookmark
the correct card. A feature that should be part of any sane web app.
I cannot wait till we can use things like this in all browsers. It will surely make the web a richer experience. Once again, I’d like to thank the WebKit team for a totally excellent web browser and for pushing the web foward. I don’t know
what I would do without you