Service Workers: Going beyond the page

Ali and I announce Service Worker and Progressive Web App support on the Microsoft Edge blog:

We’re thrilled to announce that today’s Windows Insider build enables Service Workers by default in Microsoft Edge for the first time.

This is an exciting milestone for us and for the web! These new APIs allow the web to offer better experiences when devices are offline or have limited connectivity, and to send push notifications even when the page or browser isn’t open.

This milestone also establishes the foundation for full-featured Progressive Web App experiences in Microsoft Edge and the Microsoft Store. We’ve carefully tailored our implementation together with Windows and are excited to be the only browser on Windows 10 to provide push handling in the background to optimize for better battery usage. We’ll have more to share about PWAs on Windows in the weeks ahead, so be sure to stay tuned!

We believe Service Workers are a foundational new tool for the web with the potential to usher in a new golden age of web apps. You can try out web experiences powered by Service Workers in Microsoft Edge on starting with today’s Windows Insider release, 17063.

The state of the web

Not too long ago, the web’s capabilities were lagging behind what native apps could do. Browser vendors, standards bodies, and the web community have relentlessly attacked this gap over the last decade, with the goal of enabling richer web experiences.

A particularly egregious sore spot for the web has always been how it handled—or failed to handle—the lack of an internet connection, or a poor-quality connection. Offline and the web never really went well together—in most cases, we were given a frustrating error page that only made it clearer that the web’s greatest asset was also its greatest weakness: the internet. In contrast, native apps are typically designed to provide a good experience even while offline or experiencing spotty service.

On top of that, native apps can re-engage their users with push notifications. On the web, after the browser or the app disappears, so does your ability to deliver relevant information or updates to your users.

In the rearview: Application Cache

By 2012, we were able to do offline on the web by introducing a new standard: Application Cache (or App Cache for short). A site author could list URLs for the browser to keep in a special cache called the App Cache so that when you visited the page you would see something other than an infuriating error page that would make you want to smash your keyboard and throw it against the wall.

Unfortunately, this wasn’t the silver bullet we were looking for in terms of bringing offline to the web. There are more than a few well-documented limitations for App Cache that made it confusing and error prone for many users and web developers. The sum of it all was that there was little control in how the App Cache would work since most of the logic occurred behind-the-scenes in the browser.

That meant if you ran into an issue, it would be exceedingly difficult to understand how to resolve it. There was an obvious need for something that gave greater control to developers by offering the capabilities of App Cache but made it more programmatic and dynamic while doing away with many of its limitations that made it difficult to debug.

Hit Rewind

App Cache left a lot to be desired. For the next swing at enabling offline scenarios, it was clear that browsers needed to provide web developers true control over what would happen when a page and its sub-resources were downloaded, rather than having it automatically and transparently handled in the browser.

With the ability to intercept network requests from a page and to prescribe what to do with each, site authors would be able to respond back to the page with a resource that it could use. Before we get there, it seems that we would need to revisit one of the most fundamental aspects of the web: fetching a resource.

How fetching!

As you may recall from my last post on Fetch, we now have the fetch() method as well as the Request and Response primitives. As a refresher, here’s how you might retrieve some JSON data using the fetch API:


fetch('weather.json')
.then(function(response) {
if (response.headers.get('content-type') == 'application/json') {
return response.json();
} else {
throw new TypeError();
}
})
.then(processJSON);

view raw

sw-1.js

hosted with ❤ by GitHub

Every request that happens on a page (including the initial navigation, CSS, images, scripts and XHR) is defined as a fetch. The fetch() method (as shown in the code sample) is just a way to explicitly initiate a fetch, while implicit fetches occur when loading a page and all of its sub-resources.

Since we’ve unified the concepts of fetching resources across the web platform, we can provide site authors the chance to define their own behavior via a centralized algorithm. So, how do we pass that control over to you?

Service worker: the worker that serves

Web workers have long been a great tool to offload intensive JavaScript to a separate execution context that doesn’t block the UI nor interaction with the page. Given the right conditions, we can repurpose the concept of a web worker to allow a developer to write logic in response to a fetch occurring on a page. This worker wouldn’t just be a web worker, though. It deserves a new name: Service worker.

A service worker, like a web worker, is written in a JavaScript file. In the script, you can define an event listener for the fetch event. This event is special, in that it gets fired every time the page makes a request for a resource. In the handler for the fetch event, a developer will have access to the actual Request being made.


self.onfetch = function(event) {
event.respondWith(
fetch(event.request);
);
}

view raw

sw-2.js

hosted with ❤ by GitHub

You can choose to respond with a fetch for the provided Request using the JavaScript APIs which returns a Response back to the page. Doing this essentially follows the typical browser behavior for that request—it’s not intrinsically useful to just do a fetch for the request, ideally it would be more useful if we save previous Response objects for later.

Cache it!

The Cache API allows us to look up a specific Request and get its associated Response object. The APIs give access to a new underlying key/value storage mechanism, where the key is a Request object and the value is a Response object. The underlying caches are separate from the browser’s HTTP cache and are origin-bound (meaning that they are isolated based on scheme://hostname:port) so that you cannot access caches outside of your origin. Each origin can define multiple different caches with different names. The APIs allow you asynchronously open and manipulate the caches by making use of Promises:


caches.open('my-cache').then(function(cache) {
return cache.addAll([
'/index.html',
'/styles.css',
'/main.js'
]);
})

view raw

sw-3.js

hosted with ❤ by GitHub

These caches are completely managed by the developer, including updating the entries and purging them when they’re no longer needed – this allows you to rely on what will be there when you may not necessarily be connected to the internet.

Although the Caches API is defined as part of the Service Worker spec, it can also be accessed from the main page.

So now you have two asynchronous storage APIs to choose from: Indexed DB and the Caches API. In general, if what you’re trying to store is URL-addressable, use the Caches API; for everything else, use Indexed DB.

Now that we have a way to save those Response objects for later use, we’re in business!

Back to the worker

With a service worker, we can intercept the request and respond from cache. This gives us the ability to improve page load performance and reliability, as well as to offer an offline experience. You can choose to let the fetch go through to the internet as is, or to get something from the cache using the Cache API.

The first step to using a service worker is to register it on the page. You can do this by first feature-detecting and then calling the necessary APIs:


<script>
if (navigator.serviceWorker) {
navigator.serviceWorker.register('sw.js', {scope: '/'})
.then(
function (registration) {
console.log('Service worker registered!');
},
function (err) {
console.error('Installation failed!', err);
}
);
}
</script>

view raw

sw-4.js

hosted with ❤ by GitHub

As part of the registration, you’ll need to specify the location of the service worker script file and define the scope. The scope is used to define the range of URLs that you want the service worker to control. After a service worker is registered, the browser will keep track of the service worker and the scope it is registered to.

Upon navigating to a page, the browser will check if a service worker is registered for that page based on the scope. If so, the page will go on to use that service worker until it is navigated away or closed. In such a case, the page is said to be controlled by that service worker. Otherwise, the page will instead use the network as usual, and will not be controlled by a service worker.

Upon registration, the service worker won’t control the page that registered it. It will take control if you refresh the page or you open a new page that’s within its scope.

After initiating the registration of a service worker, it will go through the registration process. That will involve going through the different phases of its lifecycle.

The service worker lifecycle

Let’s unpack the different phases of the service worker’s lifecycle, starting with what happens once you try to register it:

  • Installing: This is the first step that any service worker goes through. After the JavaScript file has been downloaded and parsed by the browser, it will run the install event of your script. That’s when you’ll want to get everything ready such as priming your caches.

In the following example, the oninstall event handler in the service worker will create a cache called “static-v1” and add all the static resources of the page to the cache for later use by the fetch handler.


self.oninstall = function(event) {
event.waitUntil(
caches.open('static-v1').then(function(cache) {
return cache.addAll([
'/',
'/index.html',
'/styles.css',
'/main.js',
'/fallback.html'
]);
})
);
}

view raw

sw-5.js

hosted with ❤ by GitHub

  • Installed: At this point, the setup is complete, and the service worker is awaiting all pages/iframes (clients) that are controlled by this service worker registration to be closed so that it can be activated. It could be potentially problematic to change the service worker for pages that are still actively using a previous version of the service worker, so the browser will instead wait until they’ve been navigated away or closed.
  • Activating: Once no clients are controlled by the service worker registration (or if you called the skipWaiting API), the service worker goes to the activating phase. This will run the activate event in the service worker which will give you the opportunity to clean up after the previous workers that may have left things behind, such as stale caches.

In this example, the onactivate event handler in the service worker will remove all caches that are not named “static-v1.”


self.onactivate = function(event) {
var keepList = ['static-v1'];
event.waitUntil(
caches.keys().then(function(cacheNameList) {
return Promise.all(cacheNameList.map(function(cacheName) {
if (keepList.indexOf(cacheName) === -1) {
return caches.delete(cacheName);
}
}));
})
);
}

view raw

sw-6.js

hosted with ❤ by GitHub

  • Activated: Once it’s been activated, the service worker can now handle fetch and other events as well!

In this example, the onfetch event handler in the service worker will respond back to the page with a match from the cache if it exists and if there isn’t an entry in the cache, it will defer to making a fetch to the internet instead. If that fetch fails, it will resort to returning a fallback.


self.onfetch = function(event) {
event.respondWith(
caches.match(event.request).then(function(response) {
return response || fetch(event.request).catch(function() {
return caches.match('/fallback.htm1');
});
})
);
}

view raw

sw-7.js

hosted with ❤ by GitHub

  • Redundant: The final phase of the service worker is when it is being replaced by another service worker because there’s a new one available that is going to take its place.

There’s more to it: the big picture

So far, we’ve explored the following service worker events: install, activate, and fetch. Install and activate are considered lifetime events while fetch is considered a functional event. What if we could expand on the service worker’s programming model and introduce other functional events that could plug in to it? Given that service workers are event-driven and are not tied down to the lifetime of a page, we could add other events such as push and notificationclick which would present the necessary APIs to enable push notifications on the web.

Push it to the limit

Push notifications provide a mechanism for developers to inform their users in a timely, power-efficient and dependable way, that re-engages them with customized and relevant content. Compared to current web notifications, a push notification can be delivered to a user without needing the browser/app or page to be opened.

The W3C Push API and Notification API go hand-in-hand to enable push notifications in modern browsers. The Push API is used to set up a push subscription and is invoked when a message is pushed to the corresponding service worker. The service worker then is responsible for showing a notification to the user using the Notification API and reacting to user interaction with the notification.

A standardized method of message delivery is also important for the W3C Push API to work consistently across all major browsers where application servers will need to use multiple push services. For instance, Google Chrome and Mozilla Firefox use Firebase Cloud Messaging (FCM) and Mozilla Cloud Services (MCS), respectively while Microsoft Edge relies on the Windows Push Notification Service (WNS) to deliver push messages. To reach reasonable interoperability with other browsers’ messaging services, WNS has now deployed support for the Web Push protocols being finalized within IETF, as well as the Message Encryption spec and the Voluntary Application Server Identification (VAPID) spec for web push. Web developers can now use the Web Push APIs and service workers to provide an interoperable push service on the web.

To start, you’ll first need to make sure your web server is setup to send pushes. The Web-Push open-source library is a great reference for anyone new to web push. The contributors have done a reasonable job in keeping up with the IETF specs. After starting up a node.js server based on the web-push library, you’ll need to setup the VAPID keys. Keep in mind that you’ll need to use HTTPS as it is required for service workers and push. You only need to set up the VAPID keys once which can be generated easily using the corresponding function in the web-push library.


var webpush = require('web-push');
var vapidKeys = { publicKey: 'BL6As_YCGHPf3ZeDbklyVxgvJVb4Tr5qjZFS-J7XzkT5zQNghd9iUBUsqSlVO5znwTsZZrEOx8JFRDJc1JmkymA',
privateKey: 'GnMVDgbtZrqs7tgKEkJaV5aZF8cVjoq7Ncz_TEVI_lo'};
webpush.setVapidDetails(
'mailto:myaccount@hotmail.com',
vapidKeys.publicKey,
vapidKeys.privateKey
);

view raw

sw-8.js

hosted with ❤ by GitHub

Once that’s all sorted out, it’s time to take advantage of push in your site or app. Once the page loads, the first thing you’ll want to do is get the public key from the application server so that you can set up the push subscription.


function urlBase64ToUint8Array(base64String) {
const padding = '='.repeat((4 base64String.length % 4) % 4);
const base64 = (base64String + padding)
.replace(/\-/g, '+')
.replace(/_/g, '/');
const rawData = window.atob(base64);
const outputArray = new Uint8Array(rawData.length);
for (let i = 0; i < rawData.length; ++i) {
outputArray[i] = rawData.charCodeAt(i);
}
return outputArray;
}
fetch('./app_pubkey')
.then(function(res) {
res.json().then(function(data) {
var appPubkey = data.key;
registerPush(urlBase64ToUint8Array(appPubkey));
});
});

view raw

sw-9.js

hosted with ❤ by GitHub

With the public key in hand, as before, we’ll need to install the service worker, but this time, we’ll also create a push subscription.


function registerPush(appPubkey) {
if (navigator.serviceWorker) {
navigator.serviceWorker.register('sw.js')
.then(function(reg) {
return reg.pushManager.getSubscription().then(function(subscription) {
if (subscription) {
return subscription;
}
return registration.pushManager.subscribe({
userVisibleOnly: true, applicationServerKey: appPubkey
});
});
})
}
}

view raw

sw-10.js

hosted with ❤ by GitHub

Before a new push subscription is created, Microsoft Edge will check whether a user granted permission to receive notifications. If not, the user will be prompted by the browser for permission. You can read more about permission management in an earlier post about Web Notifications in Microsoft Edge. From a user’s perspective, it’s not obvious whether a notification will be shown via the page or through a push service, so we are using the same permission for both types of notifications.

To create a push subscription, you’ll need to set the userVisibleOnly option to “true” – meaning a notification must be shown as a result of a push – and provide a valid applicationServerKey. If there is already a push subscription, there is no need to subscribe again.

At any point when a push is received by the client, a corresponding service worker is run to handle the event. As part of this push handling, a notification must be shown so that the user understands that something is potentially happening in the background.


self.onpush = function(event) {
event.waitUntil(
registration.showNotification('WEATHER ADVISORY', {
body: event.data ? event.data.text() : 'no payload',
icon: 'icon.png'
})
);
}

view raw

sw-11.js

hosted with ❤ by GitHub

Of course, after a notification is shown, there is still the matter of dealing with when its been clicked. As such, we need to have another event listener in the service worker that would handle this case.


self.onnotificationclick = function(event) {
event.notification.close();
event.waitUntil(clients.openWindow('weather/advisory'));
}

view raw

sw-12.js

hosted with ❤ by GitHub

In this case, we first dismiss the notification and then we can choose to open a window to the intended destination. You’re also able to sort through the already open windows and focus one of those, or perhaps even navigate an existing window.

Push: The Next Generation

As part of our ongoing commitment to expanding the possibilities of the web, Microsoft Edge and PWAs in Windows will handle these service worker push event handlers in the background. That’s right, there’s no need for Microsoft Edge or your PWA to be running for the push to be handled. That’s because we’ve integrated with Windows to allow for a more holistic approach to push notifications. By leveraging Windows’ time-tested process lifetime management, we’re able to offer a system that reacts appropriately to system pressures such as low battery or high CPU and memory usage.

For our users it means better resource management and battery life expectations. For our developers, it means a push event handler that will get to run to completion without interruption from a user action such as closing the browser window or app. Note that a service worker instance that is running in the foreground for the fetch event will not be the same as the one in the background handling the push event.

Notifications in Microsoft Edge and PWAs will be integrated in the Windows Action Center. If you receive a notification and didn’t get the chance to act on it, it will get tucked away into the Action Center for later. That means that notifications never get left unseen. On top of that, the Action Center will group multiple notifications coming from the same domain so that users have an easier time sorting through them.

Service worker: properties

I’d like to take a moment to go over some things you should keep in mind when using service workers in your web app or site. In no particular order, here they are:

  • HTTPS-only. Service workers will not work in HTTP; you will need to use HTTPS. Fortunately, if you’re testing locally, you’re allowed to register service workers on localhost.
  • No DOM access is allowed. As with web workers, you don’t get access to the page’s object model. This means that if you need to change something about the page, you’ll need to use postMessage from the service worker to the page so that you can handle it DOM changes from the page.
  • Executes separate from page. Because these scripts are not tied to the lifetime of a page, it’s important to understand that they do not share the same context as the page. Aside from not having access to the DOM (as stated earlier), they won’t have access to the same variables available on the page.
  • Trumps App Cache. Service workers and App Cache don’t play well together. App Cache will be ignored when service worker is in use. Service workers were meant to give more control to the web developer. Imagine if you had to deal with the magic of App Cache while you’re trying to step through the logic of your service worker.
  • Script can’t be on CDN. The JavaScript file for the service worker can’t be hosted on a Content Distribution Network (CDN), it must be on the same domain as the page. However, if you like, you can import scripts from your CDN.
  • Can be terminated any time. Remember that service workers are meant to be short-lived and their lifetime is tied to events. In particular, service workers have a time limit in which they must finish executing their event handlers. In other cases, the browser or the operating system may choose to terminate a service worker that impacts the battery, CPU, or memory consumption. In either case, it would be prudent to not rely on global variables in the service worker in case a different service worker instance is used on a subsequent event that’s being handled.
  • Only asynchronous requests allowed. Synchronous XHR is not allowed here! Neither is localStorage, so it’s best to make use of Indexed DB and the new Caches API described earlier.
  • Service worker to scope is 1:1. You’ll only be able to have one service worker per scope. That means if you try to register a different service worker for a scope that already has a service worker, that service worker will be updated.

Recap

As you can see, service workers are so much more than an HTTP proxy, they are in fact a web app model that enable event-driven JavaScript to run independent of web pages. Service workers were brought in to the web platform as a necessity to solve offline, but it’s clear that they can do so much more as we continue to extend their capabilities to solve other scenarios. Today we have push, but in the future, there will be other exciting capabilities that will bring the web that much closer to offering the captivating and reliable experiences we’ve always wanted.

Go put a worker to work!

So, what are you waiting for? Go and install the latest windows insider preview build and test out service workers in Microsoft Edge today. We’d love to hear your feedback, so please file bugs as you see them!

— Ali Alabbas, Program Manager, Microsoft Edge
— Jatinder Mann, Program Manager, Microsoft Edge

Advertisement

Build 2012: 50 Performance Tricks to make your HTML5 apps and sites faster

Creating high performance web applications is crucial for every web developer, be it a web site that runs on a standards based web browser or a Windows Store App. Microsoft recently hosted the BUILD 2012 conference at the Microsoft campus in Redmond, WA. At this conference, I had the opportunity to share the Internet Explorer team’s favorite 50 performance tips to make HTML5 apps and sites faster. If you weren’t able to attend the conference, I recommend you check out the video.

Video link to the Build 2012 session: 50 Performance Tricks to make your HTML5 app and sites faster.

These performance tips and tricks apply equally to web sites that run on standards based web browsers, and Windows Store Apps, which are also just the web. There are six principals detailed in the talk that will help you improve the performance of your apps and sites today:

  1. Quickly response to network requests
  2. Minimize bytes downloaded
  3. Efficiently structure markup
  4. Optimize media usage
  5. Write fast JavaScript
  6. Know what your application is doing

I hope you enjoy the talk.

Thanks,
Jatinder Mann

Nuclear Fission Powered Web Browsing

For the last 8 years, every Windows machine has shipped with a Graphics Proccessing Unit (GPU). A GPU is a specialized circuit designed to accelerate creating images to output to the computer display. Whether it’s a super powerful gaming rig, or a small compact netbook, there’s a GPU in there. And for the last decade, GPUs have gotten exponentially faster, at a rate much higher than CPUs. Today, much of that processing power is wasted because applications don’t use it.

When the Internet Explorer team was reading the HTML5 spec, we saw the potential of using the GPU to improve performance and we built our implementation of Internet Explorer 9 with the GPU in mind. That means that we offload work from the CPU to the GPU whenever we can, to make use of the graphics card.

To help demonstrate the power of hardware accelerated HTML5, I wrote the following Particle Acceleration demo on the IE Test Drive site. I like to think of it as nuclear fission powered web browsing. Check it out!

If you own a touch monitor, doing the swipe gesture will accelerate the molecules in that direction until inertia slows it back down. Pinching will let you expand the particles and double tapping will make the entire setup explode. With a mouse, clicking and dragging has the same effect as the swipe gesture and clicking in the center does the explode.

This entire demo was written with HTML5 Canvas and JavaScript – no WebGL was used. I have used the Rotation Matrix to multiple my 3D coordinate space to get the motion here. Karlito Bonnevie and I have documented the model on MSDN.

Particle Acceleration IE Test Drive Demo

New to HTML5 Canvas? Try out Canvas Pad

If you are new to HTML5 Canvas, I recommend you try out a tool I created on the IE Test Drive site called Canvas Pad.

If you’ve seen the Test Drive demos for hardware accelerated Canvas graphics, you are probably excited by the potential of this technology and want to learn more about it. With all major browsers supporting HTML5 Canvas, a scriptable 2D drawing context, Canvas is quickly becoming the natural choice for graphics on the web.

Even though the Canvas API, as defined in the HTML5 2D Context spec, has less than a hundred methods, attributes and interfaces, sometimes it’s easier to learn a technology by looking at sample code and simple demos.

Canvas Pad attempts to fulfill these needs. As the Internet Explorer Program Manager for Canvas, I find myself answering a lot of questions on how to do things in Canvas – I have seen great results by just pointing people to this tool.

As you can see from the image below, this site contains both a view of the actual Canvas and a script console containing the code generating the Canvas context. You can update the code and make real-time updates to the Canvas.

Canvas Pad

The Canvas Pad demo shows both the Canvas and sample code that you can manipulate.

Canvas Pad contains 22 samples on shapes, color/styles, line styles, shadows, text, images/videos, transformations, animations and mouse movement, which you can click through on the left hand pane. Further, below each sample, there is a reference to the API signature and the 2D Context spec definition of the API you are looking at.

I have found quite a few of my friends finding this tool useful to learn Canvas.  If I want to tinker with a new idea, sometimes I just open this up and drop some quick code. Try it out yourself!

Jatinder Mann

IEBlog: Debugging Common Canvas Issues

I wrote this article on the IEBlog discussing common Canvas debugging issues:

8 Sep 2010 3:12 PM

As we’ve previously discussed, IE9 includes support for HTML5 canvas. You can test it out right now by downloading the latest platform preview. In our testing of sites that use the latest web standards, we are pleased to see that many canvas sites just work in IE9. For those of you using <canvas> on your site, we have two tips to make sure it works properly across browsers and in IE9: use feature detection instead of browser detection, and use <!DOCTYPE html>.

Be sure to use feature detection instead of browser detection

If you are using browser detection, such as automatically falling back to a non-canvas implementation if you detect that the user is using an IE User Agent string, you may be blocking HTML5 content from rendering in IE9. Instead of doing browser detection, you should
do feature detection
to check if the user’s browser has a certain capability. For instance, you can use this code to check if your user’s browser supports canvas:

 
var canvas = document.createElement("canvas"); 
if (canvas.getContext && canvas.getContext("2d")) 
{ 
   // Code requiring canvas support 
} 
else 
{ 
   // Canvas isn't available. Put non-canvas fallback here 
} 

This eliminates the need for you to make assumptions about current browser feature support and ensures your site will continue to work as browsers evolve. We explain more about feature detection in this post.

How to check if the user’s browser supports Canvas:

  • DO: Canvas feature detection code
  • DON’T: Browser detection using User Agent string
  • DON’T: Conditional comments

Make sure your site is in IE9 mode

By default, if your site is following web standards, such as using a standards DOCTYPE, IE9 will render it in standards mode. You can check if your site is in this mode by bringing up the Developer Tools (press F12) and checking to see if your site is in IE9 standards Document Mode.

Canvas is a new feature only supported in IE9 standards mode – a design decision we took to ensure that legacy document modes remain fully backward compatible. If you see a Document Mode for your site other than IE9 standards, HTML5 elements like canvas won’t be displayed. For example, if you don’t have a DOCTYPE in your page, IE9 will display the site in Quirks Mode. To ensure your page works as expected in IE9, we recommend that you add a strict DOCTYPE to your webpages. For example, you could add the W3C HTML5 DOCTYPE:

<!DOCTYPE html>

Or you can use a common strict DOCTYPE such as this:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">

You can read more about how IE determines the document mode here.

Interoperability and Canvas

Interoperability is a high priority for IE9, to the point where we recommend sending IE9 the same standards-based markup your site sends to other browsers. Most canvas sites should just work on IE9 if the site was originally developed for another browser. That being said, there are a few behavior differences between browsers. For instance, consider the shadow demo from the Canvas Pad test drive site.

This is one example of a canvas feature that is rendered a little differently in each browser. We are making IE9 interoperable whenever possible, but for some canvas features, other browsers do not have a complete or correct implementation. In these cases, we follow the W3C spec. We submit test cases to the W3C as a way to help ensure everyone agrees on how the spec should be interpreted and implemented. To learn more about our shadow implementation, check out our canvas tests from the IE Test Center.

The purpose of the W3C spec is to define a standard that all browsers should follow. If we find examples where browsers uniformly behave differently from the spec, we feel that spec should be updated to reflect the interoperable behavior, if it makes sense for web developers. For instance, HTMLFrameElement did not contain the contentWindow attribute in the W3C spec; however IE8, Firefox, and Chrome all support this attribute. We filed a bug with a proposed change, and the HTML5 editor updated the latest revision of the spec.

If something looks unexpected in IE9 and you believe it is an interoperability issue or an area where we deviate from the spec, please let us know by filing a bug with Microsoft Connect. One of our goals around the platform previews and the beta of IE9 is to give our users a chance to give us as much feedback as possible, so don’t hesitate to let us know if you think you see a bug!

Thanks,

Elizabeth Ford and Jatinder Mann

Program Managers, Internet Explorer

IEBlog: IE9 Includes Hardware Accelerated Canvas

In this IEBlog post, Paul and I announce Internet Explorer 9 support for HTML5 Canvas:

1 Jul 2010 6:24 PM

With the recent release of the latest IE9 platform preview, we talked about how we’re rebuilding the browser to use the power of your whole PC to browse the web, and to unlock a new class of HTML5 applications. One area that developers are especially excited about is the potential of HTML5 canvas. Like all of the graphics in IE9, canvas is hardware accelerated through Windows and the GPU. In this blog post we discuss some of the details behind canvas and the kinds of things developers can build.

Canvas enables everything from basic shapes to fully interactive graphics

Canvas is a way to program graphics on the web. The <canvas> tag is an immediate mode 2d drawing surface that web developers can use to deliver things like real time graphs, animations or interactive games without requiring any extra downloads.

At the most basic level, canvas enables you to draw primitives like lines, rectangles, arcs, Bezier curves, quadratic curves, images and video like the following:

This image is a simulation of what you’d see in a canvas enabled browser.

Please use the IE9 preview to see these examples running in canvas.

The Canvas Pad demo on the IE test drive site goes into detail on the canvas syntax and enables you to easily experiment with a wide range of examples. Feel free to make changes to any of the samples that are there to see how it works — for example, try changing colors or sizes of things.

Taking things a step further, you can use JavaScript to animate canvas drawings or make interactive experiences. The next example draws lines as you move your mouse (or as you move your finger on touch enabled devices) over the black box. You could also choose to have your canvas experience react to keyboard input, mouse clicks or any browser event.

This image is a simulation of what you’d see in a canvas enabled browser.

With canvas support in IE9, you can move your mouse over the black box and draw lines.

By utilizing the full power of the PC with hardware acceleration for graphics and fast JavaScript for animation, web developers can use IE9 to build deep, graphically rich experiences. Since canvas is an element like other elements in HTML, it participates in the page layout and its API is exposed to JavaScript so it can be fully incorporated into a web page’s design. This makes it possible for sites to include things like live data visualizations, games, splash pages and ads without the need for any extra downloads or plugins.

The IE testdrive site includes several examples that demonstrate the kinds of things that sites are now able to do in an interoperable way.

Shopping

The Amazon Shelf shows what shopping for books could look like when the web site designer is able to use the kind of graphics, animations and smooth transitions that canvas enables.

Immersive game experiences:

The following demos showcase some gaming concepts like physics, character animation, collision detection and mouse interaction coupled with hardware accelerated graphics. In these demos, you’ll notice that not all browsers can update the screen with the same frequency (FPS or frames per second). IE is able to maintain a high FPS by using Windows technologies to make use of your GPU – your computer’s hardware that’s optimized for rendering graphics.

FishIE Tank

This demo makes use of sprites to animate the fish and basic collision logic to redirect the fish when they hit the edges of the tank. It’s also good for measuring graphics performance because you can change the number of fish to increase or decrease the graphics load.

Asteroid Belt

The asteroid in the demo follows your mouse, scales and rotates. It’s an example of direct interactivity that you might find in a game.

Mr. Potato Gun

A physics engine in this demo defines how the different parts of Mr. Potato head are launched from the gun and then how they react when they bounce off the ground. Many games use some form of physics engine like this to manage particle movement and their response.

Canvas Zoom

This demo enables you to start with a very wide angle on an image like this mountain range and then zoom in very close image like people at a picnic. For games, it’s an interesting example of scaling and smooth transitions.

Demos from around the web:

There are some pretty amazing demos floating around the web and I’d like to share a couple of our favorites — there are many more. An important part of implementing canvas is that we do it in an interoperable way so that developers can use the same markup. To help achieve this goal, we’re always looking for examples that work and those that don’t. A future canvas blog post will go into detail about how we work to be interoperable and what we do when there’s an issue reported.

I hope you enjoy some of these canvas examples from people around the web.

Cloth Simulation

This demo is interactive and the cloth is responsive to movement and gravity.

Zwibbler

The shapes in this drawing app are preserved so you can select and then move, resize, or change their styling.

Liquid Particles

The particles in this demo are drawn to or repelled from the mouse.

Kaleidoscope

This one does a nice job of drawing you in – it’s engaging and interesting to watch the patterns as they evolve.

Nebula Visualization

The alpha blending used by this demo are really well done. The result is a cloudy atmospheric look. It’s graphics intensive and it’s still very fast and smooth in IE9.

Animated Reflection

The author of this demo says, “The script is currently using 80% of my cpu so it’s not really practical. Hopefully we will be getting JIT’d javascript sometime soon.” Well, now JavaScript is compiled in IE9. It generally uses about 1% of my CPU.

Asteroids in Canvas

This is a full game with nice graphics, collision detection, keyboard interactivity, score keeping and… green lasers.

Particle Animation

See your name in lights. This is another demo that includes a particle system. You can run this with 300 or 1500 sprites. Go ahead and bump it up to 1500.

We’re looking forward to seeing the kinds visual experiences web developers will be able to build with a fully hardware accelerated browser.

Give it a try yourself. Watch the videos, get the latest platfrom preview, try out the canvas demos and build some examples of your own. If you find a bug in how canvas works or where the same markup behaves differently, please report bugs on Connect.

– Thanks, Paul Cutsinger and Jatinder Mann

Deep Dive into HTML5 Canvas

My MIX11 talk, Deep Dive into HTML5 <canvas>, is now available online for viewing on the Channel 9 MSDN site.

The topics covered in this talk are:

  • What is Canvas and when to use it?
  • Drawing Model
  • Security Model
  • Accessibility features
  • Interoperability differences between browsers
  • Best practices for coding and performance

MIX11: Deep Dive into HTML5 <canvas> session

MIX 2011

I will be giving a talk about HTML5 Canvas at this year’s MIX11 conference – tune into the webcast. I will share details after the talk.

Deep Dive Into HTML5 <canvas>

Breakers H
Mandalay Bay, Las Vegas
Wed, Apr 13 11:30 AM12:30 PM

If you’ve seen the demos for Internet Explorer 9’s hardware accelerated graphics, you are probably excited to learn the details of HTML5 Canvas. With all major browsers supporting HTML5 Canvas, a scriptable 2D drawing context, Canvas is quickly becoming the natural choice for graphics on the web.  In this session, you will learn advanced Canvas concepts (including the origin-clean security and the Canvas Drawing Model), understand when to use Canvas versus SVG and get a deeper look at how the Internet Explorer team solved interoperability issues as we implemented the specification. You will learn to build HTML5 Canvas websites through best practices and lots of code samples.