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-503
$eventId
ID of event: wwdc2011
$eventContentId
ID of session without event part: 503
$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 503] Hidden Gems...

WWDC11 • Session 503

Hidden Gems for Web Apps

Internet & Web • iOS, OS X • 48:24

Did you know that you can use JavaScript to recognize touches and gestures, fetch or monitor a user's location, and detect motion through the accelerometer and gyroscope? Learn how to add features like these to your web page or app to enable a enhanced user experience. See how to add and optimize home screen icons and splash screens for web apps, and learn the best practices for displaying your web app in fullscreen mode.

Speakers: Anton D'Auria, Matt Lilek

Unlisted on Apple Developer site

Downloads from Apple

HD Video (640.7 MB)

Transcript

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

Hi, everyone. Welcome to WWDC. I'm Anton D'Auria. I'm an engineer at iOS Safari and WebKit. And today, we're going to talk about hidden gems for web apps and how you can make your web apps look great on iOS. Safari revolutionized the way we experience the mobile web. It was the first mobile browser that showed us the real internet.

And it took a step further and allowed us to touch the web with intuitive gestures. And for developers, Safari pioneered HTML5 technologies like CSS3 transforms, transitions, animations, audio/video tags that make it simple and easier to make beautiful interactive websites. But there are other technologies that you can take advantage of in your web apps, and that's what we'll discuss today.

So what you'll learn today, what are we going to go over? First, touch and gestures, how you can add intuitive UI that users are familiar with. We're going to talk about geolocation, making your apps aware of where the user is, adding greater context to your app. We'll talk about motion, making your app aware of how the user is holding the device, how they're physically interacting with it. And we'll go over how you can make your web app work offline and faster online. And in addition to the HTML5 technologies, we'll also go over some ways in which you can make your app look really good in iOS as an iOS app.

Over the course of the talk, we're going to take a website, which we call Destinations, that shows us beautiful sites around the world, and we're going to transform it into an iOS web app that will be aware of where the user is, what's relevant to them, It's going to be aware of how the user is holding the device, so it'll have an orientation, and it'll work offline, and it'll look great as an iOS app.

So first, touch and gestures. They've been available for years on iOS, and users have come to expect that. They know how to use touch and gestures. But you may ask, is it really available in JavaScript, HTML, and CSS? Yes, it is. But before we dive into the Destinations project, I think it's simpler to start with a small example, and I'd like to show you how I use touch and gestures on just two DOM elements.

So I'm switching to a demo. Here, overhead display. And here you see a simple website. And I place a finger down. And this site is actually tracking my finger. You can see with the blue circle. It's aware of my finger moving and tracking it. This would be impossible with mouse events.

I can place a finger down, and I can start moving around with a little bit of JavaScript and CSS. I can move divs around. I can also design gestures that make sense in my app. Like I want a color change gesture. So with a two finger tap, I change the color of that div. And users are also familiar with pinch and zoom, when your app has things that can be enlarged, like photos or maps. And just placing two fingers down, I can start scaling and rotating. And you can see as my fingers move apart, I'm enlarging.

And I'm rotating. And so you can make custom gestures with touch events. And touch events play nicely with the new system gestures on iOS that allow you to Open up the multitasking bar, which you can see here. Or if the user decides to do a four-finger pinch to close the app, your app will be able to handle that case as well.

How do we do this in JavaScript? Well, I'd like to tell you a little bit about the touch event model in JavaScript. First, when you place a finger down, a touch start event is fired. As the finger moves, touch move events fire, and when you lift the finger from the screen, touch end fires.

If a user gets a phone call on iPhone, or he performs a system gesture, or the screen is dimmed, a touch cancel event comes in. And this is especially important for you to handle because you'll need to update the state of your UI that responds to touch events.

And if you have any custom gestures, you'll need to update the state of those recognizers with touch cancel. So let's see, what actually-- what do we have to write in JavaScript? So let's say when we track three fingers. Start with touch start. We add an event listener for a touch start event, and we have our callback handle touch start.

In our callback, we get a touch event object. What does the object look like? The touch event object has three properties. First, a list of touches representing each finger. that are present on the screen during this event. Then we have another list. I call it Change Touches, and it only contains touch objects for the fingers that have moved since the last event.

And the next property is another list, target touches. This contains touch objects that are on the element that is listening to touch events. So let's go over this again. Three fingers are down. We have three elements in the touches on touch start. Then, if only one of the three fingers has moved, change touches has one object, one touch object.

And if all three fingers are still on the element that is listening to the touch events, target touches will have three touches. And so in this case, when I had my two fingers on the red div, how many touch objects were there? Two. One for each finger. So what do the touch objects actually look like? What are their properties? First, the identifier, which distinctly identifies each touch that is down. It allows you to track the fingers. Here they are.

What is the target of the touches? Two touches are on the red div. The target is the red div. All right. Then we see the screen X and screen Y, page X and page Y. It's a little bit easier to use a smaller screen to distinguish between the two. So finger comes down. Screen X and screen Y are with respect to the top left of the screen.

And if you have a large page on which you're scrolling, page X and page Y will be with respect to the top left of the actual page, not the screen. So here's the difference between screen X and screen Y, page X and page Y. What can you use touch events for? Well, unlike with mouse events, you can actually track multiple fingers.

And you can make custom event, custom touch, custom gestures, like as you've seen me add, the change color gesture with a two-finger tap. And what did it take to make the two-finger tap? Had a touch start. Both fingers were on the same element. So target touches is of length two. The fingers did not move.

And they were lifted immediately with no preceding touch movements. So it's that simple to make gestures that make sense for your app. Well, what about pinch to zoom? You have photos, maps, very intuitive gesture for users. You saw me perform Pitch and Zoom. Do you really have to do all the math? No, you don't. It is provided as a gesture event. It's a special event in JavaScript.

And here's what the events look like. First, you get a gesture start as soon as the second finger comes down on the screen. As the fingers move, gesture events-- gesture change-- gesture change events are fired. And when one of the fingers is lifted, gesture change event comes in.

And so here in my example on the red div, I was performing a gesture change event-- gesture change. And this is what the JavaScript would look like. You add an event listener for gesture change, And your callback will receive this object, this gesture event object. It'll have just a few things. Scale, which gets larger as the fingers move apart.

and smaller as the fingers move together, and rotation, which is in degrees, as the fingers move clockwise. The degrees are positive. And as you move counterclockwise, the degrees become negative. So how do we use scale and rotation? to actually rotate that div. We used WebKit transforms in this way.

Our scale and rotate box callback simply does a WebKit transform. It takes the event scale and the event rotation, applies the transform. But you'll notice there's a start rotation and a start scale. These are important because the WebKit transforms are not cumulative. And so you need to multiply in a start scale from a previous gesture event that has ended, and a start rotation, and add in the start rotation from the previous event.

And that is because when you begin a gesture event, The scale starts at 1, and the rotation angle starts at 0. So adjust your end. You will save the scale and you'll save the rotation. You'll multiply in the scale and you'll add in the rotation. So for the next gesture start, you can continue where you left off with the previous gesture event.

So you may have noticed that in my demo, the page wasn't bouncing around when I was moving the fingers around the page. It wasn't rubber banding as you're used to seeing in Safari. And that's because I prevented the default Safari behavior for touch move events. And you'll want to do this too in your app. So to prevent scrolling, you'll add an event listener. for TouchMove, and you'll prevent default browser behavior by calling prevent default on the event.

I also want to remind you to keep your touch event handlers simple. Let them come in. You schedule what you want to get done with set interval. Try to avoid moving things around that will cause relay outs. But applying transforms, as I've done, to scale and rotate is actually very fast, and it's fine. It's fine to do in your touch event handlers. And now I'd like to invite on stage my colleague at Apple, Matt Lilek. Welcome, Matt.

Hello, everyone. As Anton showed you earlier, I wrote this Destinations app a few years ago. And let me show you the old version. This is it. Like I said, I wrote it a few years ago. The iPhone was brand new. I really only had the desktop in mind.

And it looks okay on the iPad, but I can't really interact with it at all. I can't pinch to zoom on any of these photos or anything. It just doesn't feel like an iOS app should. So I'm going to fix that today. And the first thing I'm going to do is pull up my code here.

And Each photo on screen is represented by this Photo JavaScript class. And within that class, the actual DOM is a development and then an image element inside of that. So what I'm going to do is I'm going to add a touch gesture listener so that when I pinch on the image, it's going to expand and I can see it more clearly. So what I'm going to do here is in my code, I'm going to listen to the gesture end event on my image, and then I'm going to implement a simple callback.

And what this does is it looks at the scale property from the event object that were passed at gesture end. And if the scale is larger than one, that means that the user has expanded their fingers outward. And I'm going to enlarge the image using my set scale little helper function, which just applies a CSS transform to it. And if it's less than one, I'm just going to scale it back. So I'm going to save this and switch back to my iPad and pull up the-- New version, which you can see I've simplified already.

And I can scroll it using standard overflow scroll now with one finger. And I can pinch to zoom in on these, as you can see. And in only half a dozen lines of code, I've already made my app far more interactive than it was before. And it was just really simple. And Anton can tell us more.

All right, so what did we just learn? With touch and gestures, you can make your UI more interactive and intuitive with multi-touch. You have the touch event for tracking multiple fingers and also making your own custom gestures that make sense with your app. For pinch and zoom, you have the gesture event, which you can use to pinch, zoom, rotate, and use when you have graphics, just where you have maps, things that users want to grab and scale and rotate.

I want to remind you again to handle touch cancel if you're using touch events, to update the state of your UI in case there's an interruption from phone calls or system gestures, Don't forget to prevent scrolling with prevent default, and keep your touch event handlers simple to not block other touch events.

And most importantly, try it. It's easy. Improve your UI instantly on iPad and iPhone. So we've made these changes to the Destinations app. We made it easier to look at photos, simplified the UI. But wouldn't it be great if we could just know what are the awesome destinations within city limits within our web app? And we can do this with geolocation.

You can do this in your web app right now. Phones are everywhere, and you can take advantage of this. Add a lot of contacts. There are great APIs out there, Twitter API, Flickr API. You can enrich your app with this. So how do we use geolocation? What is it like? So the geolocation interface is an asynchronous JavaScript API.

And you can--so you can do multiple things. First, you can find out where the user is right away. You get an approximation with getCurrentPosition. As the user moves, you can be alerted of his changing location with watch position. You'll provide a callback. Your callback will fire when the GPS determines the user has moved.

And when your UI is done using watch position, make sure to clear it. This is important, and we'll get back to it shortly. So using cache position is important as well. You would use it to not wake up the GPS, and if you don't need very precise position. You call getCurrentPosition on navigator geolocation, provide success callback and error callback, and you'll notice the maximum age set to, in this case, 10 minutes.

If a cache position is available, it'll return instantly. And it will--something like this. Your success callback will look something like that. And make sure to provide an error callback, because the user may decide to not authorize your app or your security origin, your domain, from knowing about their location. Also, of course, the user may be indoors, and the GPS may time out.

So how would we use it? So how would we use watch position? Because Get Current Position is fast, it's also less precise. And so what you would do is you'd provide your callback to watch position, you'd get a watch ID, And once you're satisfied with zeroing in on the user's location, you will need to call ClearWatch with that watch ID. This is important, and you need to use this responsibly because keeping the GPS radio up uses power.

And of course, remember, a user can-- a user is asked every 24 hours whether they'll allow your security origin, your domain, to know about their location, and so they can decline every 24 hours. And Matt, I'd like to welcome you again to show how we use location in destinations. Hello again, everyone. So as we saw before, there's a lot of photos here on our web app.

And it's really inconvenient to have to scroll through all these. I mean, there's places from New York and Tokyo and San Francisco all around here. So what I'm going to do is I'm going to use this little button I've got in my web app up here to allow the user to only show images that are close to them.

So how do I do that? In my code, I've got this application JavaScript class, which handles loading photos and handles rotation, just some other stuff. And what I'm going to do is I'm going to, when I load the page, I'm going to get that button. I'm going to add a touch end event to that. And in my callback, I'm going to use navigator.geolocation.getcurrentposition to get the user's location.

I only want to know generally where they're at because I just, you know, Beijing is far away from New York. I don't need to use watch position to track them, so I may as well not waste the battery. So I've got two callbacks here, success and error, and what do I do in those? Well, if the user authorizes me and we get a location... I've got this code that I wrote earlier, which queries our database for the location, the latitude and longitude of the photos.

And I provide that, the coordinates from the position object that is returned to us. And then once I've got that information, I just loop over all the photos that I've got on screen and either hide them or keep them visible for the user. And in the case of an error, or we don't have permission, I just simply get that button again and make it look disabled for the user. So what does that actually look like? Let's switch back to this. That one. So I'm just going to reload this.

And when I tap on this button, An alert's going to pop up asking if Safari can use my location. This is the first time I've used geolocation within Safari, so iOS needs to ask permission for the app itself to use geolocation, and I'm just going to tap OK. And then... There we go. The website is going to prompt for permission.

We have to do that because you can load a lot of sites in Safari. You can -- a lot of websites can use geolocation, and you don't want to necessarily authorize every single one of them just by default. I'm going to tap okay. And my photos are going to disappear. And now I only see ones from around San Francisco.

And that was only maybe another dozen lines of code. And it's just already a lot easier to use my web app. So I will give it back to Anton. Thanks, Matt. So we saw how you can use geolocation to make your app aware of the user's context, where they are, and show them what's relevant to them in the moment.

So with location-- with the Geolocation API, you can determine the user's location, and as they move, your app can know about it. You can make sure to handle errors because, specifically with GPS, you will not always be able to find out where the user is. And be mindful of power consumption.

This is true for all devices, and got to use this API responsibly. So now we've simplified the UI significantly. We use geolocation as a gesture, as an input, as a UI input. But wouldn't it be great if the user takes the device and points it within their city limits and to see what are the great things that lie ahead? What are the noteworthy things to see that are in front of them? And we can do this with orientation and motion.

iOS developers, iOS app developers have used Orientation in Motion to create all sorts of innovative, interesting apps that were previously unimaginable. And you can do this with JavaScript and HTML and CSS in your web apps. You may think, well, I already have window.orientation. I already can provide the onOrientationChange callback and know if the user is holding it portrait or landscape. But that's not what we're interested in today.

Portrait and landscape just tells you 90 degrees, zero degrees. You know, it just tells you how the user's holding it with respect to portrait and landscape. But we want to actually know, how are they moving it in their 3D space? How are they leaning it forward or back? Or what if they're shaking it? That's motion. But first, we start with device orientation, and we have precisely how it's held. And device motion tells us how did the user move the device? What are the forces they applied to it to move it? So first, let's look at orientation.

If I want to listen to changes in orientation, I listen to device orientation event. When it fires, my callback runs on orientation, and I get this device orientation event object. And what's in this object? Well, quite a lot. We see alpha, beta, gamma. These are ranges and degrees that represent the three dimensions. What is alpha? Imagine pinning the device on its back, and it's spinning around like this. As it moves, you will get degrees in alpha, starting with zero when the app loads, and as the user moves it around, like this, the alpha value will change.

Beta represents rotation around the x-axis. So if you put the green arrow through the device and lean it forward like this, you will see rotations on the beta value. You will see beta value changing, and it will represent the rotations there on the x-axis. And then for y-axis, imagine the device rotating like this with the orange arrow through it, and that's gamma.

Now, you'll also notice two properties, WebKit Compass Heading and WebKit Compass Accuracy. These are new in iOS 5. And WebKit Compass Heading tells you where, with respect to magnetic north, is the device facing. So you can use this without waking up the GPS, without using geolocation. You'll know where the user is heading with WebKit Compass Heading. WebKit Compass Accuracy tells you how confident is the platform of that reading and if there's magnetic interference. Don't use alpha, which tells you how the user is rotating like this, for compass heading. That's because alpha starts at zero when your app loads.

And this is supported by iPad 2, iPhone 4, and the latest iPod Touch. Well, what about Shake? How do we detect Shake? And for this, device motion is the perfect thing to use. It also has quite a bit, but for this purpose, we'll use acceleration, which is in meters per second squared, and it's what are the Gs along X, Y, and Z axes? And then what is the rate of velocity change? The next value is acceleration, including gravity. And that's acceleration with gravity factored in to the three axes.

And in the spirit of how is the device moving, we also get rotation rate, which tells us how did the device rotate along x, y, and z since the last device motion event. How did it move in terms of those angles, alpha, beta, and gamma, that we just went over? And that interval is in milliseconds since the last event fired. And now I'd like to turn it over to Matt so he can show you how we use orientation in destinations.

Hello again. So as you've seen, we've been able to simplify and enhance our web app already. But one thing that we thought would be cool is to give the device or to give our web app a different kind of feel in the landscape orientation. And what we're going to do is we're going to, in landscape, when the user rotates the device around, we're going to make it so that there's a little compass on screen, and it shows what lies ahead in that direction. So in order to do that, I'm going to go back to my code here. And in my application, I want to, Add an event listener for the device orientation event.

And in my callback for that, I'm going I'm going to do a couple of things. First, I'm going to get the WebKit Compass Heading property from the event that's passed to us. And then I'm going to have a little digital compass in the screen. And in order to do that, I'm just going to use that compass heading and update the direction on screen, as well as the kind of north or south string for that.

And then I've got some other code in my application that determines the direction based off of the heading property, and then looks at all of the photos in our database and figures out which one the user should be seeing and shows that on screen. So let's see what that looks like.

So if I rotate this to landscape, you can see that we've got the direction that we're facing, as well as an image up here. And as I rotate it around, you can see that it changes. If we go north, you can see that we're looking towards the Golden Gate Bridge, which you can't really see up there.

And it's pretty cool to use this. But if you're limited in your movement, it's kind of awkward to use. Or say you don't want to have to spin around 360 degrees to see all the photos. So what we want to do is make it so that when you shake the device, a random photo pops up and you can cycle through the photos that way.

So in order to do that, we're going to go back to our code one more time. And just like we've been doing, we're going to add an event listener and provide it a callback, just like we've done before, this time for the device motion event. And in that callback, what we're going to do is... We're going to take a look at the acceleration from the event. And in my case, I'm only concerned about the acceleration along one axis. Your app may be different. You might want to use all three. You'll probably definitely want to use all three depending on your use case. But this is good enough for my situation.

And I'm just going to get the force from that based off of the other motion events that have been passed to us. Because you're going to get a lot of motion events every single time the user moves the device. So in order to make the determination on whether it was a shake or not, we're going to look at a couple of things. One, if the force exceeds the force that we want to consider a shake. In my case, it's real low. Again, that's going to depend on your use case and your application.

Okay, that, and then after, we're only concerned about shakes, possible shakes, within the last half second, because we don't want a slow shake to be considered a shake in our case. So if those conditions are met, we're going to use some other code that we've got in our application that just pulls out a random photo and updates it on screen. So let's take a look at what that looks like. And I'm going to reload this one more time.

You can see as I move the device-- let's block the orientation there. As we move the device, we get a new photo. Yes, no, maybe. It's a little iffy on stage here, but you get the idea. You'll be able to do it in your app a lot easier than up here with a bunch of magnetic interference. So that was, again, only a few lines of code. So let's have Anton tell us some more.

Thanks, Matt. So orientation and motion, really amazing. You can add A new gesture, pointing the device. That's a new gesture that is possible for web apps. It's pretty incredible. So what did we do? What did we learn? Orientation tells us how precisely the device is held as the device is moving to know how--oh, sorry. Remember, WebKit Compass Heading is what you'll use for Magnetic North for geodirection, and Motion-- Motion tells us how the device moved in a span of time. So it tells us meters per second squared along three axes, and also how the rotation changed in that time.

So now we have this great app for discovering places to go and see, but wouldn't it be great if we could just take it and go and not be dependent on a network connection? And there are some HTML5 technologies that you can use to do this, to accomplish this. And I just want to go over one, which I think is really great. It's HTML5 Application Cache.

It'll make your app run offline, and when your app is online, it'll run much faster. It won't need to pull down anything. Your app is updated as a single unit, so no one element in the app could be out of sync with another. These updates are atomic. And you don't need to write much code to support this. Actually, you don't need to write any code at all.

And you can also control if you want to go out and get things from the Twitter API or Flickr API. You can allow your app to do that. And as your app generates content for the user-- with the user, you can use other persistent storage technologies like Web SQL databases and local storage. We're not going to go into the details on this today, but there's an excellent session on Thursday. called Using HTML5 Offline Storage. And if you're serious about making web apps, you've got to check this out.

So now we've taken this app, this website, and we've turned it into an interactive app that tells us in the moment where we could go, what we can see. It has an intuitive UI, but it's still running in the browser. We can make this an iOS app, and I'm going to tell you a few tips for that. How your app can look great in iOS. We're going to talk about using CSS for different orientations and resolutions.

will talk about how you can launch your web app from the home screen and how to make that process look really good. Make all your graphics, like icons, look good on different screens. And we're going to talk about startup images. So first, resolution-specific CSS. You already probably separate style from content using CSS. You can also separate CSS just for resolutions and just for different orientations.

Because you might want certain styles for portrait or landscape, and you may want to load high-resolution images just for retina display devices and low-resolution images just for iPod Touch or 3GS. And so you'll use media queries, CSS media queries, for this. How does it work? In your main resource, you'll provide a link tag That will have a media attribute, which is a string that is evaluated as the browser is determining whether to load the link or not. That string is evaluated, and if it's evaluated to true, that iPhone 4 CSS file will be loaded. And that's the media query for iPhone 4.

And you see for iPhone 3GS, you simply negate the pixel ratio 2, which is the iPhone 4-specific media query, and only that CSS file will load and not the iPhone 4 on 3GS. And for iPad, this is the media query for iPad. This is extremely useful because you don't want to load the pings that are high res for iPhone 4 when you're on 3GS.

Now, what about the orientations? You want your app to lay out-- you want to control how your app lays out in different orientations. And you may think, OK, I'll just add a link tag that will add orientation. An orientation-- just use the AND operator and specify the orientation.

Well, actually, in the link tag, that's not enough. Because link tags, as I said, when the main resource is loaded, the link tag-- the media attribute is evaluated. And if it's not in the right orientation, if it's in portrait, landscape will not load. So what you'll need to do is inline CSS. Inline CSS in the resolution-specific CSS files. So for a retina display, you'll have the orientation portrait style. And you'll have the orientation landscape style.

Okay, so now we have the separation of styles. We know how to lay things out for different resolutions, but we still have to enter a URL. Still have to enter a URL. It's still in the browser. Well, you could--you could do-- you could actually escape Safari and save a bookmark on the home screen and make it launch like a real app. So we're gonna go over this now. How to launch from your home screen. You'll see in the action button, you can get-- you have an option to add to home screen.

And that will add an icon. And in your app, you can actually find out if the user is in standalone mode without Safari UI, which we'll go into next, and guide them to the action button using this check, if navigator standalone. Your home screen icons will be-- should support-- must support, I should say, Retina display and the normal-- and the 3GS and iPod Touch displays. You can specify this with Apple Touch icon relation. Use the sizes attribute for iPad and iPhone 4 so your icons look great on the home screen. If you don't want the default icon gloss that's applied to all icons, Add this relation and the reference to your ping.

So we talked about the standalone-- bringing the app to the home screen and checking for standalone mode. You can remove Safari UI if your app is launched from the home screen, and you provide this meta tag in your main resource. From the home screen, your app will be launched with your high-res icon for retina display, and with this meta tag, your app will launch. Your web app will look just like an iOS app.

Now you have your app launching, and you may think, well, the status bar, the status bar color really conflicts with my application. You actually have three colors to choose from for your status bar. Black, black translucent, and default. To make sure it looks great, And that's, again, a meta tag in the main resource.

If you have links in your web app, which you probably do if you haven't yet turned it into an iOS web app, if you have links to other pages, Even if it's on your security origin, if it's in your domain, those links will open in Safari. So you should design your web app to use HTML-- XML HTTP request to pull in resources from your-- from your site without launching Safari. And that's how you stay out of Safari.

And because this is a web app, when a user hits on the home screen icon, it takes some time to load all the resources. And as that time passes, what happens now by default? Well, we show you a screenshot of what the web app looked like last. When the web app was closed, We actually -- and it reopened. We actually reload the web app on launch.

And so what could happen is a jarring transition between the last screenshot of your app and reloaded state of your app. And to avoid that kind of transition, you can add startup images. So as your app loads, you'll show something that's -- you know, show something that looks good.

And you can do this for iPhone and iPod Touch only in portrait orientation. And you'll use media queries This is the relation you use, Apple Touch Startup Image, and you provide the media query that you're all familiar with now for iPhone 3GS and iPod Touch, and you start a ping.

And for Retina Display, that's the resolution you'll use, 640 by 920. And again, you'll use the media query for iPhone 4 for Retina Display. On iPad, though, the startup image could be orientation specific. Again, you'll use media queries, and you have to provide exact image dimensions. 768 by 10, 4 for portrait. Again, it's that Apple Touch Startup image relation. And for landscape, 1024 by 748.

So we went over how to make your web app look good on iOS. First, we provide CSS that's specific for resolutions and CSS specific for different orientations. We went over how to launch your app as an iOS app from the home screen with-- Correct resolution of icons with the correct color of the title bar of the status bar.

And as your app loads, we show a startup image. So now we've gone from a website that had a cluttered UI that was in Safari to a standalone web app that's interactive, has gestures, is orientation and location aware. And we used HTML5 technologies and some tricks in iOS. With touch and gestures, you can create intuitive UI in your app. With geolocation, you can make your app aware of where the user is, who's near him, what's around. Adds a lot of context to your web app.

You can use motion and orientation to add a new sense to your app. Your app can be aware of how the user is holding it, how they're shaking it physically, add a lot of interactivity to your web app. You can use HTML5 application cache to bring your app offline, and it can look really good just as an iOS app. So now you have everything you need to know to make rich, dynamic, interactive websites, web apps on iOS. And I look forward to seeing what you guys come up with. Thank you.

If you have any questions, contact Vicki Murley, our Safari Technologies Evangelist. Check out Safari Dev Center documentation. And don't be afraid to look at the W3C spec. It's a great resource to find out how web browsers work. Upcoming session, HTML5 Offline Storage. You've got to see that. It's on Thursday.