CSS Effects, Part 2: Galleries and 3D Effects

Session 504 WWDC 2010

You can create rich, interactive media galleries for Safari on iPhone OS and the desktop using standard web technologies such as CSS transitions and animations. See how to deliver a first-rate immersive experience by positioning and animating webpage elements in 3D space, controlling keyframes within animations, and listening for animation events to trigger other actions on the page. Understand how to deliver these effects with a minimal amount of code, and discover tips and tricks for great performance.

Simon Fraser: Hi, my name is Simon Fraser and I'm an engineer on the Safari and WebKit team.

And you probably saw the first in this two-part series on CSS effects by Jing just now.

This is part two.

And in this session we're going to focus on some slightly more complex systems effects using a photo gallery as an example.

But we'll look at keyframe animations and 3D effects in some amount of detail.

Now you've probably heard the term HTML5 a lot in the news recently.

And as we mentioned, HTML5 formally is the name of a specification, which is the next version of HTML5.

But informally, it's being used to cover a sort of fairly broad range of web technologies.

And today we're going to learn how to use one of those web technologies, CSS3, to create some really rich, immersive web experiences.

And you'll learn how to get really good performance and really nice animation, both on iPhone, iPad, and on the desktop.

And then we'll be using a little bit of JavaScript to sort of glue things together and to create some of the really cool effects.

So we first released support for dynamic CSS effects in Safari 3.1 and in iPhone 2.0.

And it's been really interesting to see what people have used them for.

Of course on www.apple.com we've been putting these effects to great effect, creating lot of really neat interactive content that lets people look at the new products and see all the details about them.

And there are also people outside of Apple who have been using these effects.

This is the page from www.panic.com that describes the Transmit application.

And this makes really good use of transitions, transforms, and animations to let users explore the features of this application.

So from inside a web page, the user can really get a feel for what it's like to use the actual application once they've downloaded it.

And then in the State of the Union yesterday, you saw the HTML5 demos.

These, again, make great use of CSS effects so I encourage you to go and explore those and to download the code for those.

So all of this stuff, you know, obviously is just web development.

If you already know a little bit of CSS cascading style sheets it's a very small amount of additional knowledge to use CSS effects and really spice up your pages.

In this session, pretty much everything I'm going to talk to you about is CSS properties.

There's a little bit of use of the document object model that's the DOM API.

And that's the API you use from JavaScript to modify the page, listen for events, and things like that.

And of course JavaScript is the programming language that we use to drive all this stuff.

And all of this works in Safari on iOS or on iPad, iPhone, and iPod touch, and of course Safari on Mac and Windows.

And then if you're embedding WebKit in your native apps, in UIWebView, in iOS, and WebView on the desktop, all this stuff works as well.

And also, there's another client now iAds.

So if you're creating iAds, you'll probably make really strong use of CSS effects.

So let me take a minute to talk about open standards, and you've probably heard this before, but I want to reinforce it.

The way Apple advances web technology is to participate in open standards and specifically we work with the standards groups.

For example, we've worked very closely with the WHATWG Group and the HTML working group of the W3C on the HTML5 specification, particularly in terms of the audio and video elements.

I'm actually a member of the CSS working group and all the properties that I'm going to talk about today are included in specifications that we've submitted to the working group for consideration, for inclusion in CSS3.

Now because these are still specifications in draft form, we do have the WebKit prefix on the properties and Jean mentioned in the previous talk why we have this prefix.

So let me show you or tell you what you'll learn in today's session.

We're going to focus on two demos and use those to explain to you what CSS effects you can use and why you want to use them.

The first one is what we call a lightbox.

It's a simple image viewer.

You're probably really familiar with this you go to a page with images or a gallery, you click on those images, and then get this sort of full screen overlay or full window overlay and you focus just on the image.

And in creating this lightbox, we'll see how simple it is to use CSS transitions.

And we'll show you how to get consistent behavior between iPhone, iPad, and desktop.

Now the second example is a photo gallery, and this has some more dynamic content.

We're loading images dynamically, there's a bit more JavaScript.

But we'll use this as a vehicle to show you the really cool effects you can do with transitions, animations, and transforms some really nice cinematic stuff.

And throughout the session I'll give you some tips and tricks.

So to show you these two demos that we built, I'd like to invite my colleague, Enrica Casucci on stage to give you a demo.

[ Applause ]

Enrica Casucci: Hi, everyone.

I'm going to show you today a simple example of a lightbox.

As Simon said, a lightbox is a technique normally used to display large images on top of a page using an overlay.

It's something that looks more or less like this.

Normally, the larger image is presented with a variety of transitions, animations for positioning and sizing.

And there's a number of existing frameworks that you can use in order to easily add this functionality to your pages.

The one we have used for this example is called FancyBox.

But let's take a look a little bit closely at the transition here.

As I tap on the image, as you can see the transition to the large image is not extremely smooth.

And let me do this one more time.

Notice that when the overlay comes up, there is no opacity animation on the background.

And also, normally these frameworks provide some sort of loading indicator while the large image is being loaded.

And let me show you this one slowly.

As you can see, the progress indicator looks fairly static.

What happens here is that even though I mean, this is a great framework, don't get me wrong but the problem that we are encountering here is that JavaScript is used to drive the animation.

What this means is that we normally have JavaScript timers firing for each frame of the animation.

Using CSS transitions and animation allow us to basically let the rendering engine in the browser do the heavy lifting for us, taking advantage of the existing hardware and potentially leveraging hardware acceleration when it's available.

So let me show you now another example of another page we've created using only CSS transitions and animations.

Again, the look is very similar but as I tap over the image, look how smooth the transition is.

We've used a scaling transition here.

Let me do this one more time so that you can fully appreciate.

And also check out the transition on the opacity of the overlay, which adds a very nice touch and a polished look.

And if I show you this first one that I've created with a slow motion, look how smooth the progress animation is.

And this is because we are truly leveraging the power of the hardware acceleration.

During the second part of the session, Simon is going to talk about photo galleries and you will learn how to use 2D and 3D transforms and animations to create some awesome effects.

Since you're all developers, I'm pretty sure that at this point you all want to jump to the code and take a look.

But I want to tease you a little bit longer.

Here is an example of a photo gallery that we have created to showcase some of the effects that you can achieve with CSS transforms and animation.

Using a transform on the opacity, you can create a crossfade effect like this.

Transform with translations allow you to create push effects like this or a push down like this one.

With rotation, you can achieve spin effects but it's when you start using 3D transforms that you can truly add visual depth to your photo gallery.

And with the same amount of effort, you can create, like, a revolving door effect like this one, or a cube.

A few lines of JavaScript will allow you to do something like this this amazing tile drop effect, unfolding effects, sorry.

Isn't that awesome?

[ Applause ]

At this point, I'm going to hand it back to Simon, who will show you how to create these amazing things with just a few lines of CSS.

Simon Fraser: Thanks, Enrica.

That looked really good.

So let's start off by what we call building a better lightbox.

And as Enrica mentioned, there's lots of lightbox implementations out there already.

We're not trying to replicate the features of all those.

We're not trying to reinvent the lightbox but we wanted to focus on a few things here.

The first thing is: how you can make use of CSS transitions to get really nice, smooth, transition effects.

And you saw a bunch of them in the lightbox example.

The second one is: how we can create a loading indicator just with CSS.

And then finally: how to get consistent behavior and consistent performance on desktop, iPad and iPhone.

So all of this we can do in just 4 simple steps.

The first step is something that any lightbox does when the user clicks on one of the smaller images on the page, we start loading the large image.

And this is just some simple JavaScript you're probably familiar with, creating new image element, registering an onload handler so we get notified when the image loads, and then we set the source attribute to start loading the high-resolution image.

Now the key here is we want to do this as soon as possible.

We're going to have this overlay that fades in over a period of time.

So the sooner we kick off this load, the sooner the user gets to see the final image.

Okay, the second step that's to start fading in the overlay, which is this sort of semi-opaque box that covers the rest of the page so we focus on this image.

And here we start using a bit of CSS, we're matching the element with the ID overlay, using the selector right there.

And it starts off with an opacity zero, so it's transparent.

And then when we apply the visible class to that, it's going to fade to opacity 1.

And as you probably saw in CSS Effects Part 1, normally when CSS properties change, they change instantaneously.

But this gives a very jarring, kind of disruptive appearance to the user; it's much better if we can smooth out that change.

And with one line of CSS, we can do this.

We apply the transition property and we say that we want opacity to transition over a half second.

And that gives us this nice, smooth, even curve here.

And if we wanted to, we could use a linear timing function that will give us a constant rate of change in the opacity property.

So it's very easy to get animations with transitions.

And you've probably seen in fact, you have seen the shorthand used a lot, WebKit transition but these are the longhand properties.

The first one specifies which other properties you want to transition.

The second one specifies how long the transition is going to take.

And then transition timing function allows you to control that easing function and you can do custom timing functions with the cubic Bezier.

There are a bunch of easing functions built in.

And then as you saw in the previous session, transition delay, which is really useful for these neat building effects.

So let's go back to the overlay.

Now, here we have to write a little bit of JavaScript that's going to create the overlay for the first time and it uses createElement, which is one these DOM APIs.

And it sets the IDs overlay so we can identify it from JavaScript and style it in CSS.

And then we append the overlay to the body element.

Now you might think at this point that if you set the visible class name, both styles will apply, the opacity one will give a nice transition.

But in actual fact, that doesn't quite work as you expect.

So let me take a moment to explain why this doesn't behave quite as you expect.

Now the reason is: browsers actually do some style coalescing under the hood and I'll explain that with this example here.

Imagine you have this JavaScript, it's setting the background color to red and then immediately it sets the background color to blue.

Now the question is: does the browser ever actually render that red color?

And the answer is no.

The browser's essentially throwing away redundant style changes.

It batches up the style changes and red is getting overwritten with blue right away.

So the only thing it's going to do here is render that blue color.

Normally this doesn't matter but transitions are temporal.

So there's this temporal component now that means that this actually becomes important.

Imagine we changed the JavaScript to something like this.

So here we're setting the transition property and we're saying that we want background color to transition.

And now, again, do you expect to see an animation between red and blue in this case?

Well, the answer is no, we don't get one here, either and for the same reason the browser's coalescing those style changes and so the only thing the browser actually renders is the blue color.

And that transition rule is there.

And so if we change the color later on to something else, we'll get a transition but we won't actually ever see the red-to-blue transition in this case.

Now, there are a number of solutions to this problem and the one we recommend using is setTimeout.

And what this does is allow you to run a little bit of code after a delay.

In this case, we used the delay zero but it's enough of a delay that the browser gets a chance to render the initial red color.

And now when the color changes to blue a little bit later on, the browser is actually going to then run the transition between red and blue.

So you get a nice transition there.

So let's go back to our overlay.

In this case the scenario is a little different but essentially we've just appended this element to the document.

But we're applying the visible class right away so the browser's never going to have a chance to render the opacity zero.

And so it won't run that transition.

The solution is to use the setTimeout.

And now we change the class name to Visible inside the setTimeout and we'll see a nice transition here.

So that's what this looks like.

You get a nice, smooth fade, even on the iPad as Enrica showed you.

So our next step is to create this loading indicator.

You see it's static in this picture, but actually animated as you saw.

So we want to be able to animate that.

Now there are two CSS effects we can use to get a really nice, smoothly animating loading indicator here.

The first thing we can do is we can use rotations by a CSS transforms and the second one is we can use CSS keyframe animations to have this animation or this rotation continually repeat or continually animate.

And the benefit of doing it this way is: first of all, you can do it without any plugins or animated JIFs; you can use really nice, high-quality images, maybe a PNG with alpha so it lends very nicely with the rest of the page.

So let's see how we do this.

So here's our image.

And then to get the animation running, there are two things we need to do.

The first one is we describe the animation in terms of a set of keyframes.

So this uses a new at-rule and it has the -WebKit prefix.

So it's @-WebKit-keyframes.

And then the other name, spin, which we'll use later.

And the keyframes are where we described the states of the animation.

So the front keyframe is the initial state of this thing and it has a rotation of zero.

And then the 2 keyframe, the final state, has a rotation of 360 degrees, so one turn.

And then as the animation's running, the browser's going to interpolate between these two.

So they'll do a nice interpolation between 0 and 360, causing our image to spin around one time.

Now, it has this name "spin," which is some name you give it.

And then you can apply the animation, using the WebKit animation property, namely the keyframe, spin.

And then you give it a duration, so one second.

And that's the duration of one cycle of animation.

And in this case, we want this thing to spin around for as long as we're waiting for that large image to load.

So the repeat count we use here is infinite.

But you could use 10 or 5 or 1 or whatever.

And we want it to spin with a constant angular velocity so we use a linear timing function.

That gives us a nice, smooth spin out.

So that's pretty much all we need to do.

That gives us this nice spinning indicator.

And that spinning indicator is going to stay there for as long as you're waiting for the large image to load.

But once that large image loads, then the next step is to manage this transition to show the big image.

This is a little more complicated, so I'm not going to go into all the details.

But the first thing you need to bear in mind is we've got two things running here that are temporal: we've got the large image loading and the overlay is fading.

And we need to have a little bit of logic in our JavaScript that waits for both of these to finish before we do this final reveal on the image.

And you can imagine you could use CSS transitions on heightened width to do that scale of the image.

And if you wanted to, you could do transitions of maybe opacity to reveal the caption or maybe the caption could fall down where the margin transition.

And you could reveal the close button somehow, maybe it pops in with a scale.

So if you put all that stuff together, this is what it looks like, although this is what it looks like on desktop.

On iPad, you probably wouldn't get a very good frame rate.

So let me talk a bit about optimizing for iPad and iPhone.

Now, as Enrica mentioned, if you were animating properties with JavaScript, essentially many libraries do this, they're running timers to change the style of an element, you know, multiple times to get an animation to run.

The problem is the browser can't really optimize that very well; it doesn't really know what the animation is.

So if you use CSS transitions in animations, we can hit a fast path.

We know you're running an animation and therefore, we can make it a lot more efficient.

And so you'll get at least as good performance using transitions and animations on most properties and you'll get significantly better performance if you animate the transform property or the opacity properly for these we actually make use of hardware acceleration.

We offload some of the compositing to the GPU, so you get great performance with these and these are really useful for iPad and iPhone.

So let me summarize what we learned by building this better lightbox.

First of all, CSS transitions can give you a really nice cinematic experience and they're really easy to offer.

Often it's just one line of the CSS to go from a jarring transition to a nice, smooth one.

And you can get really good performance on all platforms.

Remember, the two properties you want to stick to are WebKit-transform and opacity.

And then the second thing we learned is we can get this nice, loading indicator using a combination of a rotation transform and CSS animations without any JavaScript, without any plugins.

So, you know, this lightbox is a great way of showing a single image.

What if you want to show multiple images?

Well, that takes us into the next section, which is building really awesome photo galleries.

And Enrica showed you some demos but here are some of the effects we've put together here.

Now, some of these have a sense of depth, they have some 3D in them.

And there are also some other kind of interesting effects that we can get here.

So you'll see how to build these later in this session.

So before we delve into the details of how to build a photo gallery like this, I'd like to step back a little bit and talk about best practices.

I think the most important thing when you're building a photo gallery is to stay within the same page.

If you force people to load a new page for every image as they go through a gallery, that uses a lot of bandwidth, it's very tedious for the user.

If they're on a slow connection, it will be really slow.

And there's no way you can do nice transitions between images in that case.

And you may think, "Well, if you stay on the same page doing kind of Ajax-y stuff, don't you break history and bookmarking and stuff like that?"

Well, HTML5 now has APIs that let you solve those problems it has a history API and a location object you can use to basically work around those problems of bookmarking and history.

The second thing I recommend is: load each image on demand; don't force the user to wait for all the images in the gallery to load before they can start stepping through it.

And with a little bit of JavaScript, you can just kick off those image loads as the user's moving through.

It's quite straightforward.

A technique we found very useful when creating slightly more complex content is to make extensive use of CSS class names and specifically to use class names to describe states in our content.

So in this particular example, we have two types of state we care about.

When we're moving from one image to the next, we have a new image that's coming in and we use an incoming class name to identify that, and then the old image the one that's going away and that gets the outgoing class name.

We also have the notion of initial and final states.

The initial state is where everything is before we start running that transition from the old image to the new image.

And then the final state is where everything is once we've finished that transition.

And now because we've described the states and the content using class names, our JavaScript becomes very small.

Instead of having to write a lot of spaghetti JavaScript that modifies style and does all this complicated stuff, we can use the JavaScript for two really simple things: the first is to kick off these image loads so we have the dynamic image loading, and the second thing that JavaScript does is just toggle these class names to basically move us between the states that we've already described in CSS.

So let's look at the actual markup or the structure of the document we're going to use for this gallery.

We have the main div, which we call photo container, which is just going to be the container for the images we're showing.

And then when we're running a particular move from one image to the next, we have an incoming image which would give this class name incoming and the old image that's going away gets the outgoing class name.

So temporarily, our photo container has two children two child elements which are these two images.

And when the transition's done, we'll rip out the old one and get left with just one image.

And of course to do this, so the images don't stack up, you'd use absolute positioning and that kind of thing so that they're in the right spot.

So bearing that in mind, let's see how we build a transition like this, a push down transition.

So here's our photo container.

And now we start describing the states of the content using these class names.

So the initial and final class names go on the photo container because they apply to everything underneath it.

And then here we start styling the incoming image.

And we're using transforms, of course, because we know they animate nicely.

In this case, we'll use translateY, which is just a shorthand for a vertical translate and the value is -100%.

And that's a convenient way of moving something up by its height.

So you can use percentages in translates and that's pretty useful.

When the incoming image is in the final state, it's front and center, it has a translateY(0).

And then the outgoing image starts in that same spot and moves to a positive 100% translate.

So it goes down.

And then the final thing we want to do here is, of course, tell the browser that all these style changes, these state changes, should be animated.

So we use the transition property to specify that we want transform to animate over a half-second here.

Now you may have noticed if you were looking carefully in the previous slide that we're also doing some opacity changes as we're doing this transition.

I'm not showing this here for simplicity but you can imagine it's pretty easy to add those.

So then there's some JavaScript we need to actually do the image loading and cause this transition to happen, so let's look at that.

So the first thing we do is getElementById that just gives us a reference to our photo container.

And now we start setting these class names that describe the states of things in our content.

So the outgoing image, the old image, we know is the first child of the photo container so we can add the outgoing class name to that one.

And we have the incoming image that's already loaded so we set the incoming class name on that and we're doing appendChild.

So now our photo container has two children.

And we set the initial class name to tell the browser to render all those things in their initial states.

And we use the setTimeout technique again.

And all we have to do inside the setTimeout is basically flip the class names.

So remove the initial class name, add the final class name, and that will kick off all the transitions that cause the effect to happen.

Now there's a little bit of clean up we need to do at the end.

And the first thing we need to figure out was: how do we know when this effect is finished, when the move from the old image to the new image is completed?

Well, transitions emit DOM events when they end.

So we can register an event listener, using an event listener for the WebKit transition end event.

And we register a callback function on that, which is transition done.

So let's write that now.

The first thing we do is remove the final class name.

We're done, the transition's over, we can just remove the class names; we don't need them anymore.

And then we know the first child of the photo container is the old image so we do a remove child, get rid of that.

And then we can just take the class name off the incoming image because we're done.

Now the thing to note here is that this JavaScript the JavaScript on the last two slides is not going to change for the rest of this session.

The JavaScript stays the same because we've described all of the states in CSS.

So all we have to do is change the CSS to get lots of different kinds of effects.

So let me show you some of those effects.

This is a scale transition we saw Enrica demo it, it's very simple.

And here I'm just going to show you the style for the incoming image, the outgoing image is pretty much just the reverse.

So the incoming image starts with a scale of zero, so it's like really tiny in the middle and then it zooms up to a scale of 1.

And the outgoing image just does the reverse.

And then this funky spin transition.

Being an incoming image has initial rotation of minus 180 degrees, that gives it a half turn.

And then its final rotation is zero.

And that's all we need to get that nice spin transition.

So let me summarize what we've learned from photo gallery so far.

First of all, keep your user's window the same page and then use JavaScript to dynamically load images as you move through the gallery.

Use class names to describe states.

So use this declarative technique where all the interesting states are described as combinations of CSS classes and then your JavaScript becomes really small.

All your JavaScript's doing is toggling these classes.

And then to detect when transitions end, use the transition end event.

And finally, all you have to do is change the CSS to get lots of neat transition effects.

And transforms gives you all sorts of scales and rotates you can do with the image.

So in this case we just used the transform property but we were able to get lots of different kinds of effects.

So what about these effects that look much more 3D to have this sense of depth?

Well, let's look at how to create these.

So, you know, these are obviously doing some sort of 3D stuff.

What does this mean?

We have the ability to describe 3D transforms in CSS now and this is pretty exciting.

So what it does really is it doesn't really give us a sort of 3D modeling environment we don't have spheres and cubes and cones and stuff but it does allow us to position elements in a three-dimensional space.

Sometimes this is called "planes in space or 2.5D."

And this is in addition to the x- and y-axes, you have for doing transforms already, it gives you this z-axis, which is coming out of the screen.

So, just to look at the properties for a moment, this uses the same transform property that we've been using already but it has some new values, like translate 3D, rotate 3D, scale 3D, and then there's some convenient versions of these like rotateX, rotateY.

Now 3D is a little more complex.

There's a little more setup you have to do to actually make things look 3D and handle some other issues.

So the first property here that we added is one called "perspective."

And this allows us to control a sense of depth in the scene.

And you'll see that in a moment.

The second one is useful - it's transform style is useful when you're building hierarchies of objects and you want them to live in a common three-dimensional space.

Transform style allows you to control whether there's flattening or whether these things live in a common 3D space.

And the other slightly odd thing with 3D transforms is it's actually possible to flip an element around so you can see the reverse side of it.

And sometimes you want that but sometimes you don't.

So back face visibility allows you to hide things if they've definitely flipped all the way around.

So let's go back building a revolving door effect using 3D transforms.

Now the first thing to note here is that with the revolving door effect, it's like the hinges are on the right, the elements are sort of swinging around that right-hand edge.

So there's a little bit of setup we have to do to make that work.

Now, she mentioned this in her session.

You can control the transform origin, in other words, where the origin of the transform is, and by default it's in the center of the element.

So if we rotated the element, you noticed it rotated around the center.

We can use the transform origin property to change that.

So here we've used right 50%.

So that puts the transform origin on the right-hand edge.

And you can use pixel values, percentages, or the keywords for this property.

So now when it rotates, it hinges about that right edge, which is what we want.

And then, just as before, we use these class names to set up the initial and the final states.

The incoming image is going to start basically rotated into the screen from where the user is.

So that uses a rotation about the y-axis, which is the vertical axis of 90 degrees, which pushes it back into the screen.

And then the final state of the incoming image is just flat on rotateY at 0.

And then the outgoing image, you can probably guess, starts with the rotateY at 0 and then its final state is coming out of the screen towards us, which is rotateY of minus 90 degrees.

So if we actually put that together, what would it look like?

Well, the answer is actually like this.

That was a revolving door.

This is an attempt at doing the cube transition.

And it looks very flat, you don't see any depth there.

And the reason is, we haven't described any sort of depth in this scene.

So that's where we use this perspective property that I mentioned before.

And what perspective does is it controls effectively how far away the viewer is from the plane of the screen.

And the default value is NaN, which means the viewer's infinitely far away, everything looks flat.

Then as we start setting that to actual values it's like 4,000 pixels we start getting some amount of foreshortening in the scene.

And as the perspective gets smaller, we get more and more foreshortening.

So it's as if you're getting closer and closer and you've got really sort of wild 3D in this case.

So here we add the perspective and we get a nice 3D effect.

Now, there's one thing to note here, that perspective is added on the photo container, not on the images.

Perspective affects the rendering of child elements that have transformed in 3D.

Essentially, you can think of perspective as setting up a 3D space for the elements underneath.

So far, all of the transitions we've done have been simple blends, if you like, between an initial state and a final state.

We've got some really neat ones, including 3D, but they're all just simple blends.

What if we want to do something a little more complex, like this bats animation?

Well, this is another use for keyframe animations.

We saw a keyframe animation earlier because it gave us the ability to have something that's continually repeating.

In this case, we're going to use keyframe animations because they let us specify more complex moves, using multiple keyframes.

And just like transitions, keyframe animations emit DOM events when they complete but also when they start and when they loop.

So we can hook into the same event notifications to know when our transitions are complete.

So the actual properties, you've seen these already, the @-WebKit-keyframes is where you set up the keyframes.

And then this is the longhand property here, animation name, which is where you actually apply those keyframes.

One cycle of animation or duration of one cycle is controlled by animation duration and the number of cycles by animation duration count and this has that key word "infinite" if you want to just keep going on forever.

And there's some other things you can do to control the sort of behavior when the animation is repeating.

You can have every other cycle of animation go backwards to give you some interesting back and forth behavior.

And then just like transitions, we have an animation delay property.

And we'll see a really neat use case for that in a moment.

So let's build that drop animation using some keyframes.

Here's the initial div.

And I will set up these keyframes to describe the states of the animation as the keyframe is running.

Our initial state or our from state or 0%, same thing is again, a translateY of -100%, which puts the image above the box.

And then at 70% of the way through the animation, it has a translateY(0), so it's down in the box.

And then this is how we do the little bounce: we have an 83% keyframe that moves it up by 10% and then it falls down again to 0%.

So that's enough to give us this nice little bounce effect.

And here we apply those keyframes, we're using the shorthand here, animation drop 1 second.

So this is just going to run once over1 second.

Note that we didn't change any JavaScript, so we're still using that same JavaScript code you saw earlier in the session.

So we've got these two types of animation: we've got transitions and keyframe animations.

And you're probably wondering why they are two types and why isn't it just one?

So let me compare these to explain the differences.

Now the main difference is how they're triggered.

You saw from the lightbox example that we got this nice overlay fade by changing opacity from 0 to 1 and because there was a transition rule in effect, when the opacity changed, the transition ran.

So transitions are triggered by changes in the underlying property values.

In other words, they run automatically but they're implicit.

Keyframe animations, on the other hand, run when they're applied explicitly, using the animation name property.

So you put animation name on an element and as long as that matches some keyframes, that element starts to animate.

So the notion with keyframe animations is you're really using CSS to put an element into an animating state.

So that's quite different from transitions.

Both of these use timing functions for animations or keyframe animations; the time function is within keyframes.

Of course, if you need keyframes, if you need these more complex moves with multiple points in them, keyframe animations are the way to go.

And they also allow you to have this repeating behavior, which we used for the spinning indicator and alternating behavior.

So far, the contents of our photo gallery have just been images.

But since these effects apply to any HTML element and that include video, so we could put video in our gallery if we wanted to.

We actually will you'll see that in a demo in a minute.

Or you could use SVG inside of HTML or Canvas or basically any HTML content you can apply these CSS effects to.

This gives you a lot of scope, a lot of capabilities to do neat stuff.

And actually, we're going to use this now to create this tile effect.

And I'll show you how to build this tile effect.

But here effectively what we're doing is where we had a single image before, we're going to replace that with a little subtree of nodes, using divs, to give us the tile effect.

So the way we create these tile effects are to build a div and we're going to call that "tile container" just so we can style it.

And tile container is the container for this grid of tiles.

So each of these is a div itself.

And then the way we tessellate them to make it look like they're a single image is to use background position and to set a background image.

And so we use background position to make sure that the right part of the image is rendered into each tile.

So this is a kind of thing you could do in mock-up if you wanted you could have 16 or 24 tiles as divs in your HTML content.

But this type of repetitive stuff is much better done with little bit of JavaScript.

So this is the script you would write to generate these tiles.

So we're just iterating through the rows and columns and for each tile, creating a div element.

And then we compute whether elements positioned inside the grid based on the row and column and the tile height and the tile width, which we know in advance.

And then the tiles are absolutely positioned so we can position very easily to form a grid and we do that by setting the left and top properties.

And then here's the key to make it look like it's a single image.

We set the background image property, and here I've used a hard-coded image but you probably use the next image in your slide show, which you'd feed into this function.

And then you set the background image property to minus tileX, minus tileY and that gets the correct part of the image rendered into this particular tile.

So the next thing we do we've got this grid of tiles we want to cause these tiles to animate in some interesting way.

And in this case we'll use a drop animation, which is very similar to the one we just saw.

But before we were running it on a single image; here it's running on each individual tile.

So this is the same set of keyframes.

There's a slight difference here, which is they've both added opacity.

So here opacity is going to animate between the 0% and 70% keyframes.

This just shows you that it's possible to animate multiple properties inside of keyframes you're not limited to animating just one.

And then here's where we apply the animation.

The selector's a little more complex because we have to apply this to the divs, which are direct children of the tile container when the tile container's in the incoming state.

So if we actually did that, this is what it would look like.

And we didn't see any tiles.

You know, what's up?

Well, we've got this grid of tiles but they're all animating at the same time, they're all in synchrony, so they just fall down as a block.

And that doesn't really look very interesting.

So we can add one more line to our JavaScript loop.

And that line is going to set animation delay.

So just as in the previous session, you saw a use of transition delay that causes menus to build in; here we set animation delay to cause things to happen at slightly different times.

And we're making use of Math.random, which is a JavaScript function that gives you back a random number between 0 and 1.

So this sets animation delay to somewhere between 0 and 1 second, independently for each tile.

So now when we run the transition, we get this really cool effect.

So just to summarize what we've learned from this tile effect stuff: we can replace the single image in our gallery with a grid of tile elements or a grid of divs representing tiles, and use background image and background position to have each tile render the right part of the image.

And then we see how useful delays are.

In the previous session, you saw transition delay being put to good use and here animation delay is really great for doing these neat build effects.

So at this point, I'd like to invite Enrica back to show you the gallery that we got when we put all of this stuff together.

[ Applause ]

Enrica Casucci: Hi again.

So we're back to our photo gallery example that we have seen before on my iPad.

But this time we're going to make a look at it from a Mac.

So here is a photo gallery and you've just learned from Simon how easy it is to combine CSS transforms and animations to create a series of amazing effects.

And you know, we have seen how easy it is to create a crossfade, a push, or a push down, scale transforms.

I want you to really appreciate, in this case we are using larger images than the ones we have used for the iPad demo.

And notice how smooth the transition is, even with these larger images.

But what really makes a difference is when you start using the 3D transforms because not only you create, you know, some very cool effects like this one, but it also opens up a world of possibilities in terms of what you can do to present additional content that is related to your images.

Let's say for example you want to show some text or date associated with the picture.

And so why not simply flip the image on the back and show it?

Isn't that cool?

[ Applause ]

We've seen the revolving door, the swap, and the cube.

And remember, all these transitions that we have seen up to this point, they all use the same JavaScript; we've only changed the CSS.

And as Simon mentioned, with HTML5, video elements have become first-class citizens in the web world.

So all these effects that we have seen apply to images can be applied to video elements as well, and we can have something like this.

Notice that the video is playing.

I can still flip it on the back and show my additional information while the video is still playing.

[ Applause ]

Look, now that I'm showing you the transition in slow motion that you can really appreciate that the video is playing while the transition is taking place.

I think this is absolutely awesome.

Then with a little bit of JavaScript, you can easily create this fantastic tiling effect that you have seen.

And, you know, this is just a combination of rotation with the same technique you have seen before.

But now that you know how to slice up the images, the sky's the limit.

You can create unfolding effects like this one or this one that you got a sneak preview before or something like this.

This is when you're supposed to do "Wow."

[ Applause ]

Let me show it to you one more time in slow motion so you can fully appreciate how smooth the transition is.


Enrica Casucci: Thank you.

That's what I wanted to hear.

[ Laughter ]

[ Applause ]

I hope at this point I got you all fired up and I hope I was able to communicate the excitement I have for this technology.

We have some great labs tomorrow and we hope to see you all there and come over and start playing with our sample code.

I'll give you back to Simon.

That is going to wrap up the session.

Thank you.

[ Applause ]

Simone Fraser: Thank you, Enrica.

I think that really was an awesome photo gallery.

So let me just take a moment to summarize where these things are supported.

So I talked about four categories of CSS effects today: 2D transforms, 3D transforms, transitions, and animations.

And all of these are supported on iPhone and iPad since iPhone 2.0.

Safari on Mac has supported all of these since Safari 4 and now with Safari 5, we have support across the board on Mac and Windows.

And then Chrome supports these; they don't have 3D rendering.

And some of the other browsers are catching up too, now Opera and Firefox have 2D transforms and transitions.

So let me summarize what we've learned in today's session.

First of all, using CSS transitions and animations, you can get really neat animations with very little authoring work.

In many cases, it's just one line of CSS to go from a jarring transition to a nice, smooth one.

And you can get great performance even on devices like iPhone and iPad.

And you'll get generally much better performance than you would if you used one of the JavaScript libraries that's running JavaScript time as to do animation.

And then with CSS transforms, we can position elements and transform them both in two dimensions and three dimensions.

And as Enrica mentioned, this opens all sorts of possibilities for interesting ways of user interaction, flipping things around, building things like cubes and rings.

And you've probably seen a bunch of examples and there's a lot of sample code for this.

But another great thing about animations sorry, about transforms is that they work very well with transitions and animations.

By running transitions between different types of 3D transforms, you can get all sorts of really cool effects and the animations run really smoothly.

So there's a great synergy between these two things.

And finally, not just images but as you saw, we can have great performance running these on video as well and any other HTML element.

So for more information, you can contact Vicki Murley, the Safari Technologies Evangelist.

And there's great documentation on the Safari Dev Center.

If you want to go and look at the CSS specifications and follow the workings of the CSS working group, you can look at the current work page there.

And then the Apple developer forums are another great place to go and get help.

Apple, Inc. AAPL
1 Infinite Loop Cupertino CA 95014 US