Video hosted by Apple at devstreaming-cdn.apple.com

Configure player

Close

WWDC Index does not host video files

If you have access to video files, you can configure a URL pattern to be used in a video player.

URL pattern

preview

Use any of these variables in your URL pattern, the pattern is stored in your browsers' local storage.

$id
ID of session: wwdc2011-509
$eventId
ID of event: wwdc2011
$eventContentId
ID of session without event part: 509
$eventShortId
Shortened ID of event: wwdc11
$year
Year of session: 2011
$extension
Extension of original filename: m4v
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: [2011] [Session 509] What's New ...

WWDC11 • Session 509

What's New in CSS Effects and Animations

Internet & Web • iOS, OS X • 44:14

CSS effects and animations let you add richness to any web page, and can be used inside native apps too. Learn how to combine 2D and 3D CSS transforms with CSS transitions and keyframe animations. Understand how to deliver advanced effects in just a few lines of code, discover the best practices for optimal performance, and see how to leverage new features to make your visual effects in Safari even better.

Speakers: Matthew Delaney, Jing Jin

Unlisted on Apple Developer site

Downloads from Apple

HD Video (286.4 MB)

Transcript

This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.

So good afternoon, everyone. My name is Jing Jin, and today I'm here to tell you about how to create really cool effects with CSS and the new features we added to make your life even easier. So everything I talk about today is supported on the newest Safari on desktop and Safari on iOS, available to you in the developer previews. And you should already have a basic knowledge of how HTML, CSS, and JavaScript syntax works.

So all that being said, if you're sitting here already, you probably use CSS sometime in your life. And we all know that since CSS is plain text, it's very compact to transfer over the network. It's also scalable compared to images. So for example, if you had a gradient made with CSS, it would be as crisp as it was at 100%, no matter how much the user zoomed up.

And because CSS is all interpreted by the browser, it's very optimized. And since it's plain text, you can pretty much edit it anywhere. Now, one of the benefits of CSS is that if a property isn't supported in an older browser, it simply gets ignored. So you can progressively enhance your website while staying compatible for older browsers.

And lastly, if you try to replace all of your images and plugins with CSS effects, that means all of your site is searchable from search engines. So instead of just telling you how great CSS is, I'd like to invite my colleague, Matt Delaney, up to show you a demo we made with all sorts of cool effects.

Hello, everyone. My name is Matthew Delaney. And like Jing, I'm also an engineer on the Safari WebKit team. And as you should have seen, I'll be showing you a demo today. And so this demo is full of CSS tips and tricks, absolutely chock-full. And so basically, as I go through this demo, I'm going to point out all the different CSS effects and animations that we'll later show you how to make.

So when Jing and I were going to make a demo, we were talking about how a lot of online shopping sites have a checkout process, you know, and this checkout process is usually quite tedious and, well, usually rather boring. So our demo is basically a take on-- our creative take on the checkout process. And we packed it full of different CSS effects and animations. So I'm going to show you that here now.

So as a little background, imagine you're on a kitten shopping site, for example, okay? You've just chosen all of your kittens, and you're ready to check out. So as is typical, you come up to your cart, and you see that you have all four of our kittens here.

We have super awesome kitty type number one, two, three, and four, all appropriately priced, of course. And so we've got the right cart, and so we're ready to begin checkout. Now, what's unusual about this is that as I go to begin my checkout, little do I know I'm actually inside of my order's shipping package. So this is pretty cool.

So what we did here was we created a 3D box, and we gave different faces different, basically sections of the checkout process. So what you saw was a nice sweeping transition from the inside of the box down to this new face, this first face of the box, which is quite apparent from the shipping label that it's our shipping section to fill out. So let's go and do that now. Fill out my name. And let's ship them to work. I just need some more kittens at work. And--whoops.

Here we go. There's our shipping address. So, now this page is-- this section is quite interesting because it's made entirely with CSS. There are zero images going on here at all. From--basically from the check mark that's animating as I get a field in the form correct, to this nice little yellow glowing animation I get when I get a field incorrect with the wrong number of characters, all the way to this little nice red ribbon that looks like it's wrapping itself from around the back of the shipping label to the front.

So the shipping label is one thing in particular that we'll also show you how to make later, along with the 3D box and the transitions of rotating the box. So let's continue on to the next section. So yet again, a nice sweeping transition that shows us a new face of the box. As we can see here, it's obviously the postage section. So as opposed to the usual radio button kind of selections or whatnot you see on sites, we actually have three stamps to choose from here.

So I have standard 2-day and overnight, I see. And watch this. As I mouse over each one of the stamps, I get this nice effect where the stamp appears as if it's actually peeling up off of the page. So it's pretty nice. Now, since obviously, you know, I need these kittens ASAP, I'm going to go for overnight. So as I go to choose overnight, watch this animation as the stamp actually peels itself off the page and puts itself onto the package. So that was pretty cool.

Now onto our third section here. We can see it's billing, evidenced by the credit card here. It's obviously a corporate purchase. I'm going to use my Apple corporate card, so please don't record this information. Here we go. Now this section is also of note because there are yet again zero images here. This is made entirely with CSS, everything from the credit card to all of the elements inside of the credit card that we just edited. So let's go on to the next section.

The fourth and final phase we see here is our confirmation page, which is kind of in the form of this slick-looking receipt here. So this is the usual kind of part where we're checking we have all the right information. So let's see if we have kit number one, two, three, and four. That's my favorite with the blue eyes. So I can see that it's shipped to work and paid for by work.

That's perfect. We've got overnight shipping. That's what we wanted. And the tax, that looks pretty good too. So just weighing in at a very simple $4 million, we have all four of our kittens, and we're ready to ship. So here's another thing to take note to. As I click ship it here, as my order is processing, I get this nice nifty little animation that fits the motif of our site, which is these paw prints going around a circular image, which is apparently of a cat that's processing our order.

And so this is another thing that we'll show you how to make in this talk, these nice spinners here. And if the cat would just hurry up. We get our order is complete. So it wasn't that much nicer than the alternative checkout process. So now I'm going to hand you back over to Jing, and she's going to show you how to create some of these awesome CSS effects and animations.

said I'm going to show you how to do some of those today. We'll first start with taking a look at how to create some of the graphical effects you saw there. Then I'll show you how to animate with just a few additional lines of CSS. And lastly, I'll address what's probably one of your top concerns. How do I make use of all these great effects without breaking older browsers?

So first, let's start with the effects. Some of you out there may be CSS gurus and already know that you can actually manipulate your elements in 3D space using 3D transforms. That's how we created this box. But there's also another way to create a feel of 3D without actually using 3D, and that's using 2D effects to create some lighting illusions. So for example, here we have a banner that looks like it's folded over the card. And this is actually all done with just some gradients. So we use all these properties, but gradients are great because they're very versatile.

If you remember, back in 2008, we actually pioneered the CSS gradient syntax. And now that it's being adopted by W3C standards body, we've updated our syntax to include four new functions that make it easier than ever to use gradients. So let me show you how you can use two simple linear gradients to create that ribbon-looking thing.

As you can see here, you can use gradient functions anywhere you can use images. So we use it as a background image for our ribbon here. We can give it a starting and ending color, tell the gradient which position to start in, and add in as many color stops as we need. And to position the color stops, simply add a position after each color stop separated by a space.

And with just that one additional line, we already have this folded overlook. So what about the right side? We need kind of like a diagonal taper. That's actually just another gradient overlapped with this one. So to create that, just make the top gradient transparent on the right side.

And below it, we'll add a second one that's slightly rotated and has the starting and ending colors jutted up against each other, creating a sharp edge. And here's our final effect. So like I said before, because gradients are scalable, this means that that sharp edge will stay just this sharp no matter how big your page gets zoomed up.

So that was a linear gradient. And next, onto radial gradients. This is actually my favorite type of gradient, because you can create very realistic looking three-dimensional lighting effects. So for example, the box we showed you earlier, if all we had was a background image, it would look like this.

So it's approximately the correct shape, but it doesn't look realistic because everything is the same color. And in real life, we have lights and shadows. So with a few simple radial gradients, you can turn a box that looks stiff like this to a box that looks like this.

Let's start making that. This time we'll use a radial gradient on top of a cardboard image. Just like a linear gradient, specify the start and end colors, and it will draw from the center out to the furthest corners. Adjust the colors up a little bit, and we have the correct shading for our box face.

Now for the flaps, all we need is to move that gradient from the center of the element to the top of the element. And if we wanted it to be a different shape, we can actually specify the horizontal and vertical radii separately, making a very flat ellipse. And that's all you need, two lines of gradients to create realistic lighting for your box.

So we talked about linear gradients, we talked about radial gradients, and now that you know how to use those, repeating gradients are extremely easy. Just take an existing linear gradient, add the word repeating in front of the function name, and it will repeat throughout the rest of your element. Similarly with a radial gradient, add repeating, and it repeats from inside out. So again, these four new functions or gradients, as you can see, were really simple to use. And they're available in the newest Safari 5.1 Developer Preview and the iOS 5 Preview.

Now we just created-- the last thing we did was creating shading for our box. So let's actually create the entire box now. To do this, as I said earlier, we'll use 3D transforms. And if you haven't used transforms before, it's just a CSS property that takes different functions and manipulates your element on the page without changing the layouts of the rest of the page. So for example, a translateY would move your element down without affecting its neighbors. And you can string as many of these up as you want, and they will get applied one after another.

So onto the box. Our box is an open-face box. That means we need five faces. So let's make five divs and put them in a class called package. And since we'll just want to make a square box, we'll make them 400 by 400 and absolutely positioned so they're overlapped on top of each other. Now we need to move them in 3D space. So the 3D space looks like this. The y points down, x points to the right, and z points out of the screen. So to move a face forward, we just need to apply a positive translate z to it.

Now to make one of the side faces, what we need to do is to rotate it. And that rotation is around the y-axis, so it's a rotate y. And note here that when you apply a transform function to an element, it also gets applied to the element's axis. So here the X and Z axes get rotated along with the element. And after that, a simple translate z to move it towards the right. And we've got our second phase.

So apply the same principle to the other three faces of the box, and you have your box constructed in 3D space. And on your page, it will look like that. Not really worth the effort, really. So what is happening here? This is actually because we need to apply a property called perspective. In real life, perspective is what makes things look three-dimensional. So if you look at the left and right edges of the room, you'll notice that they look like they're converging to a point, but you know that they're parallel.

And this distortion is what we need on the web page for it to look 3D. So a CSS perspective property is a value that is related to how far you are from your object. So if you're really close to your object and have a really small value, then it looks really distorted. But as you move further and further away, the object becomes flatter and flatter.

So we probably want to apply a perspective of about 800 to our box. Now note that perspective applies to the transforms of the elements children. So since we were transforming the box's face, we need to apply the perspective to the face's parents, so the class package. And applying the perspective, we now have a front-facing three-dimensional box.

So so far, I told you how to use the new gradient syntax to create some really cool effects. And we walked through how to use 3D transforms to create a box. But as you saw in the last slide, the box wasn't all that exciting. It was 3D, but if you had an opaque face, you still would see just a square. So let's add some animations to actually make it move around. One of the animations we saw was a rotation when you switched between different sections of the box. So let's take a look at that again.

Now in terms of 3D transforms, this is really just a rotate around the y-axis. So here's our box. The easiest way to rotate our box is to apply the transform to the package class. But as I just said, we need a perspective to its parent. So let's add a package container and move the perspective definition from package to package container.

Now, if we had just this, the transforms on the faces won't work. So we need to tell package that we want the faces to inherit the perspective. And we do that by using the transform style property of preserve3D. So now that we have our setup, let's do our animation. Since our animation requires one starting state and one ending state, we can translate between the two using a transition property. So for a transition property, you have your starting state and ending state.

And you can apply this in many different ways, one of which is just simply changing the class name in JavaScript. So if I change the class name from package to package right side, then what you will see on screen is that your package will snap to the right side. So with just one more line, we can add a transition property that says, I want any changes in the transform property to happen over a one second duration. This means that when we change the class back from package right side to package, we'll get a smooth transition.

Know that when you define the transition, it has no idea which position it's transitioning from and which position it's transitioning to. So it really doesn't care where your starting and ending state is. That means it's really useful if you want to use it for the same property, but a lot of different values. So for example, when we're rotating inside a box, using the exact same transition, we'll just assign a different class, and it will automatically perform the correct animation.

So that's a transition applied using JavaScript to change your classes. You can also use a transition to perform a hover effect completely without JavaScript. So for example, if you watch the bottom left corner of the stamp, when the user hovers over it, it actually lifts up. This is really just a regular class with some properties in it, and the hover pseudo class with some changes in properties, and an addition of a transition property.

So we just saw now that you can use a transition to interpolate smoothly between two states, either by using JavaScript to change classes, or by just using some pseudo class selectors. But what if you wanted something more complicated? What if, for example, you wanted the animation we had when you selected a stamp?

So as you can see here, the stamp actually flies up in front of the box and then goes back down. We can use a keyframe animation here. And to do that, first we need to determine what are the separate states of our animation. So for this animation, there are three things going on.

The first thing is that the stamp is moving smoothly from the starting state to the ending state. The second thing is that the stamp is getting a 3D transform starting at the beginning of the animation, holding it there for a little while, and then going back down to a flat stamp. And the third thing is that it's actually becoming bigger in the middle of the animation and smaller at the end. So let's watch that again in slow motion. See how it peels up, stays there, gets bigger, and then comes back down.

And on a timeline, it looks like this. You're moving from wherever the middle is to the top right. Then you're doing, it's becoming flipped, and then staying there for a quarter of the animation. And the last thing is that it's getting bigger and smaller. So as you can see on this timeline, we have four different frames we need to take care of. And now let's get to the actual coding.

So define these frames using the keyframe property. Give it a name so we can refer to it later, and put those in. Notice how I didn't put in the 0% frame. And some of you who've used keyframes before might think that's actually a mistake. But this is actually a new feature of Safari.

Any frame or any property you don't specify explicitly in a keyframe animation gets interpolated automatically by the browser. So this means when you have a really complex animation where things are happening in different orders and for different times, you can save a lot of coding. So for example, the movement we have is a smooth movement. So all we really need to do is to define the final position and not care about the other two keyframes.

All right, so we'll just add in the transforms for flipping the stamp up, and then add in a scale for making it bigger at 50%. And then we need to apply it. So here we're responding to a user click. So let's just put it in JavaScript on click handler and trigger the animation, the keyframe animation, using the animation property. So doing this, we'll get an animation that looks like this.

So the good news is we got most of the animation correct. The bad news is the stamp didn't stay there. And this is actually expected behavior in CSS animations. It means that your animation only affects your element during the 0% to 100% state. So that means when the animation finishes, the element will go back to its pre-animation state. There are some handy CSS properties we can use to prevent this from happening. And it's called an animation fill mode. So let me take a simpler example to show what a fill mode is.

Say we have a square div that's transparent, and we wanted to wait one second, then perform a pulsing animation over two seconds. With no fill mode, this means that the div will stay transparent for a second, then it will become orange, then white, then orange, and then at the very end it will snap back to a transparent value.

If we want the square to actually become orange during the one second delay, we can apply a fill mode of backwards. This means that our square will become orange for a second, then go to white and orange over two seconds, then become transparent again. And if we're on the opposite, if we want our element to stay orange after the 100% frame, like we want for the stamp, then we need a forwards fill mode.

As you can see there, it stayed at 100% frame. Now let's apply this forward fill mode to our stamp. just simply added in behind everything else. And now we have a stamp animation that correctly stays at its 100% frame. So far, I showed you how to use transitions to perform some simple interpolation between states. Then we use a keyframe animation to perform a more complex movement. Another great feature of keyframe animations is that they can repeat indefinitely. So this is great for a progress indicator when you're doing some heavy number crunching in the background.

And since we all know that the web needs more kid and child progress indicators, I want to show you how you can create this. So there are two elements on screen here, each one containing a poll. They're just rotating around the center of their container. So the keyframe animation definition for the first one is just going from 0 to 360 degrees. And since we want the second one to be slightly offset, it'll go from 5 degrees to 365 degrees.

So now we want to apply those two. We want the outside paw to start the walk first. Then we want the inside one to follow it after a delay. So for the inner paw, I added a 0.4 second delay. And I told both of them that you can rotate indefinitely. Now there's a problem here.

Since animations interpolate between frames, this means we'll get a very smooth animation. We'll get cats on ice, not actually walking. So to get the walking, one way that I've seen a lot of people do is to define a lot of keyframes. So for example, you could say, at the 10% keyframe, I want to be at 5 degrees. And at the 10.001% keyframe, I want to be at 10 degrees. So you don't get the interpolation.

But there's an easier way. Starting with the new Safari, you can use a timing function called steps. This function takes a number. And this is the number of frames you want to display for your animation. So I said I want my animation to happen over five seconds, and I want it to be divided over 10 frames evenly. This means that nothing in between will be shown, so that you get a discrete animation. And we're done.

So I showed you how you can animate with transitions, and how you can animate with keyframe animations. And you may be wondering, why is there even two different properties for pretty much just animating? Well, that's because each one is good for a different purpose. So transitions are really simple to define. It only takes one line, and it doesn't care about your starting or ending state. So as I showed you in the box, with the exact same transition, we can rotate to any side of the box.

Animations, on the other hand, require explicit definition of each of its frames, so you can't be used to rotate that box that way. But the advantage of explicitly defining frames is that you can get multiple frames out of it, and you can also tell the frames to repeat or alternate.

So remembering those will help you decide when to use a transition and when to use an animation. But if you're new to all of this, and this is a little too much to remember, just use a transition as a rule of thumb, because it's easier, and it usually does most of the things you want. So next, I'd like to get Matt back up here again, because he's going to show you how to combine transitions and animations to make something really cool.

Hi again. So now that Jing has showed us how to create all that CSS awesomeness, let's use it to build one last great thing into our demo here. So if you recall from... The first demo, as we got to the end page here, we had our confirmation page.

And as we went to ship it, we got this. We got a nice paw print processing kind of thing going on. And then when the order came back, complete, we just got this rather plain text that said, your order's complete. But how cool would it be if instead we had an animation that went something like this?

That was not a much cooler ending to our checkout process. So let's take a look at how to build that. So the first thing that's important here is to note all the different parts that are going on. So I'm going to quickly describe them to you, and then I'm going to show you the demo again.

The first thing to take note of is that there's a truck, and it drives about two seconds from the left side of the screen to the center of the screen, pauses there for about a second, and then you see it drive off to the right in about two seconds.

A second part that's going on is that the package, you see it zoom away toward the truck, and then it fades away into the truck. And the third thing that's going on is that you see very initially in the first second of the animation, the boxes flaps close into themselves and close up altogether. So let's take a look one more time.

[Transcript missing]

So we're basically, we're coordinating a few different things going on here in this animation overall. So timing is really important here. So we'll just think quickly about the timing that we want for things to kind of synchronize. So the truck animation, like I said, is basically an overall five second animation. We have two seconds in which the truck comes in, one second in which it idles there, and two seconds in which it goes off the page.

Now at the same time, we have that box zooming out, and we want it to be there right when the truck gets there. So that's basically two seconds along into the animation. Now over that third second of the animation, it's fading away. In the very first second of the animation, we saw that it's folding up. So we're going to keep that all in mind and just watch one more time in slow motion. So you see it folding up in the first second here, zooms away, then it fades away.

And the truck drives off. Cool, so let's go to the code and let's build this. So when our order is complete, we have this callback function that executes. And previously from the first demo, all it was doing was just removing the spinner, the little paw spinner there, and then it was zooming in that order complete text. So since we want to build our animation here, let's put this aside for a second. And let's add in exactly those three parts here for our animation that we want.

So step one here is the truck. So let's dive right into this. So the first thing we need to do is obviously add a little bit of markup to our HTML page for the truck. So I'm going to go and do that here in our HTML page.

[Transcript missing]

So now that we have that initial state there, all we need to do is add in our keyframe at rule for the back one of our animation.

So I'll do that right here. So I said the timing is really important, so we're just going to think about for a second which keyframes we want in order to create this animation. So we said that it takes two seconds to drive in, so the first keyframe that we want is where it's in the middle of the page after it's driven. So that'll be about 40% along the way. Now, at the third second along in the animation, it should still be there in the middle of the page, because it's basically idled over that one second.

And then the last two seconds, it drives off the page, so that's 100%. So all we need to do to add in here for each one of these Keyframes is, on the first one, left at 50%, so it's roughly in the middle of the page. And yet again, for keyframe two, we'll also have it at left 50%, so it's still there in the middle of the page.

And lastly, for keyframe three, we just need to be at left of 110%, so it actually gets pushed off the right side of the page, and yet again, not visible to the user at the end. So now that we have our keyframe at rule for our animation, for simplicity, we're just going to create a class on the truck called the drive class.

Which is just simply setting the animation to choose the @ rule that we just created, having a duration of five seconds, and using the timing function of easeInOut. So now this is as simple in our JavaScript to get this to trigger as... Just grabbing the truck element from the page using getElementById, and then adding that class name drive so that we trigger the animation. So let's take a look at that now. Make sure I save.

So now since we haven't done anything with the box just yet, it's just going to sit there. So I'm just going to very quickly open up the Web Inspector and delete the box from the page so it doesn't get in the way of our truck animation. There we go. And... Truck Drives. Perfect. So let's go back to step two.

Now, if you didn't catch everything there for the truck animation, it's OK, because it's completely orthogonal to what we're going to do for steps two and three. So let's jump to step two here. So now there's a difference between what was going on with the truck and what was going on here with the package.

And Jing went over this at the end. The difference between transitions and animations, we really don't need an animation here, because it's very simply that we have two states of the package that we're transitioning between. There's a starting state that we see with the packages in front of us. And the ending state is where the package is far away and faded out. So basically, let's go and create that ending state now in our CSS.

So we're going to create a class on the package that we'll call Zoom and Fade. And this just defines our ending state of the transition. And so we see here it just has simply just a transform that puts it in the right place very far in the page. And it sets the opacity to zero so that it's completely faded out. So now, in order to get the right transition that we want, though, between that starting state and the ending state, we're just going to define here also in the class our transitions.

So what we have here is we're just basically setting the transition property on both the transform and opacity properties. And if we keep the timing in mind again, basically what we're trying to create here is that in the very first second of our overall animation, we are waiting for the box flaps to fold up.

So we're going to have a delay on the transform, be one second, so that that happens after the flaps. And then for the opacity, we want it to fade just afterwards, the next second, so we'll make it two seconds delay. And then for the duration of each, it's just one second, as we said before.

So now, yet again, triggering this in JavaScript is just as simple as setting that class on the package. So yet again, we get the element from the page, and we have this class name, zoom and fade. And so with the right delays and the right duration, we get exactly what we want in our overall five second animation. So let's go take a look at that now. Make sure we got it right.

Zooms away, fades away. Perfect. Now back to step three. If you think about it, step three is essentially the same thing as step two. It's just a starting and ending state that we need to transition between, but now for the package's flaps. So the starting state is when they're open, and we have classes defined for that, and the ending state is when it's closed in the box. So since it's really just the same thing going on here, I'm just going to skip over it and call my little helper function that closes the flaps for us. And that's essentially just doing the same thing we did in step two.

Now we have all of our three steps, so we're going to go look at what that looks like and make sure that we got it all right. But first, there was one last thing that we have sitting over here. We commented out this function, and we want that to come in at the end to let them know that it's all done and the order's complete.

So right now, if we just called it, we would get it right in the beginning of our animation, and that wouldn't look good. So we want it to happen after our animation is done. So luckily, at our disposal, we have a DOM event that fires on the ending of animations.

So what we can do is we can add an event listener to the truck so that when its animation ends, which is basically when that ends, our overall animation is done, we call the function zoomInOrderCompleteText. So that--so we're guaranteed that that will happen right at the very end of our animation. So now let's go take a look and make sure it all worked.

So with just a few lines of CSS, we got a much cooler animation to the end there. So you might be thinking to yourself, this is pretty cool and all, and we can add these, you know, sweet animations in the newer browsers, but what about the older browsers? What do we do when, you know, perhaps we don't want it to blow up, and we don't want to break our sites and all that compatibility stuff? So now Jing is going to show you a few things that we have to rectify that. So Jing, come back up.

So as Matt said, I'm going to show you how you can use some CSS media queries to find out some properties of the device and the browser you're being displayed on. So first to detect the type of media, you can do this in HTML, CSS, or JavaScript. So in HTML, you can use the media attribute. So the code on screen here gives you an example of linking to the style sheet that has animations when we're being displayed on an actual computer screen, and just having a static style for when your web page is being printed.

With CSS, instead of the media attribute, it's just the media at rule. And this is really useful when all you need to do is to change one or two different properties. In JavaScript, you can look for the style media object on the window, and then query for its type.

So that was detecting types of media. You can also detect different types of displays. For example, you may not want your web page to look the same on a small handheld device versus a giant screen. So you can do something like, if I am on the screen and it's larger than 800 pixels, then I want to be in columns using the media attribute. Or you can do the same thing using the media at rule. And with JavaScript, you can call the match medium function and give it the exact same query you gave the HTML and CSS and perform the appropriate JavaScript there.

So the third thing you can do with CSS media queries is to detect whether certain CSS properties are supported. This is really useful for animations, because they're usually being applied via JavaScript anyways. So you can call match-medium again and give it the property you're interested in in parentheses, and only perform an animation when it's supported, and have, in the l statement, have some fallback code for older browsers.

All right, so let's see what we learned today. I showed you the newest syntax, the simplified syntax for gradients, and some examples of how to use 3D transforms. Then we animated the box we created using the 3D transform using transitions, and did some more complex stuff using keyframe animations. And just now, I showed you how to use CSS media queries to customize your code for different types of devices.

So if you have more questions, as always, feel free to contact our Safari evangelist, Vicky Murley. And last year, we actually had two different CSS sessions that made use of a lot of effects that you saw today. So they're both available on developer.apple.com, and you can download them into iTunes. Lastly, Safari Dev Center has a lot of documentation of how all of these things work.

And tomorrow we have three more Safari sessions. So if you're an extensions developer, everything I told you today can be used in a Safari extension. And of course, you probably want your dynamic web app to work well offline. And lastly, some of my colleagues will talk about how do you design your website so that it works correctly with the newest gestures online and in iOS. So thank you very much. Enjoy the rest of your conference.