object(WP_Query)#79 (47) { ["query_vars"]=> array(56) { ["tag"]=> string(5) "html5" ["error"]=> string(0) "" ["m"]=> int(0) ["p"]=> int(0) ["post_parent"]=> string(0) "" ["subpost"]=> string(0) "" ["subpost_id"]=> string(0) "" ["attachment"]=> string(0) "" ["attachment_id"]=> int(0) ["name"]=> string(0) "" ["static"]=> string(0) "" ["pagename"]=> string(0) "" ["page_id"]=> int(0) ["second"]=> string(0) "" ["minute"]=> string(0) "" ["hour"]=> string(0) "" ["day"]=> int(0) ["monthnum"]=> int(0) ["year"]=> int(0) ["w"]=> int(0) ["category_name"]=> string(0) "" ["cat"]=> string(0) "" ["tag_id"]=> string(3) "126" ["author_name"]=> string(0) "" ["feed"]=> string(0) "" ["tb"]=> string(0) "" ["paged"]=> int(0) ["comments_popup"]=> string(0) "" ["meta_key"]=> string(0) "" ["meta_value"]=> string(0) "" ["preview"]=> string(0) "" ["s"]=> string(0) "" ["sentence"]=> string(0) "" ["fields"]=> string(0) "" ["menu_order"]=> string(0) "" ["category__in"]=> array(0) { } ["category__not_in"]=> array(0) { } ["category__and"]=> array(0) { } ["post__in"]=> array(0) { } ["post__not_in"]=> array(0) { } ["tag__in"]=> array(0) { } ["tag__not_in"]=> array(0) { } ["tag__and"]=> array(0) { } ["tag_slug__in"]=> array(1) { [0]=> string(5) "html5" } ["tag_slug__and"]=> array(0) { } ["ignore_sticky_posts"]=> bool(false) ["suppress_filters"]=> bool(false) ["cache_results"]=> bool(false) ["update_post_term_cache"]=> bool(true) ["update_post_meta_cache"]=> bool(true) ["post_type"]=> string(0) "" ["posts_per_page"]=> int(15) ["nopaging"]=> bool(false) ["comments_per_page"]=> string(2) "50" ["no_found_rows"]=> bool(false) ["order"]=> string(4) "DESC" } ["tax_query"]=> object(WP_Tax_Query)#217 (2) { ["queries"]=> array(1) { [0]=> array(5) { ["taxonomy"]=> string(8) "post_tag" ["terms"]=> array(1) { [0]=> string(5) "html5" } ["include_children"]=> bool(true) ["field"]=> string(4) "slug" ["operator"]=> string(2) "IN" } } ["relation"]=> string(3) "AND" } ["meta_query"]=> object(WP_Meta_Query)#216 (2) { ["queries"]=> array(0) { } ["relation"]=> NULL } ["post_count"]=> int(15) ["current_post"]=> int(-1) ["in_the_loop"]=> bool(false) ["comment_count"]=> int(0) ["current_comment"]=> int(-1) ["found_posts"]=> string(2) "36" ["max_num_pages"]=> float(3) ["max_num_comment_pages"]=> int(0) ["is_single"]=> bool(false) ["is_preview"]=> bool(false) ["is_page"]=> bool(false) ["is_archive"]=> bool(true) ["is_date"]=> bool(false) ["is_year"]=> bool(false) ["is_month"]=> bool(false) ["is_day"]=> bool(false) ["is_time"]=> bool(false) ["is_author"]=> bool(false) ["is_category"]=> bool(false) ["is_tag"]=> bool(true) ["is_tax"]=> bool(false) ["is_search"]=> bool(false) ["is_feed"]=> bool(false) ["is_comment_feed"]=> bool(false) ["is_trackback"]=> bool(false) ["is_home"]=> bool(false) ["is_404"]=> bool(false) ["is_comments_popup"]=> bool(false) ["is_paged"]=> bool(false) ["is_admin"]=> bool(false) ["is_attachment"]=> bool(false) ["is_singular"]=> bool(false) ["is_robots"]=> bool(false) ["is_posts_page"]=> bool(false) ["is_post_type_archive"]=> bool(false) ["query_vars_hash"]=> string(32) "b127f749731aaa4cc721bc2053386347" ["query_vars_changed"]=> bool(false) ["thumbnails_cached"]=> bool(false) ["query"]=> array(1) { ["tag"]=> string(5) "html5" } ["request"]=> string(342) "SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts INNER JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id) WHERE 1=1 AND ( wp_term_relationships.term_taxonomy_id IN (127) ) AND wp_posts.post_type = 'post' AND (wp_posts.post_status = 'publish') GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC LIMIT 0, 15" ["posts"]=> &array(15) { [0]=> object(WP_Post)#229 (25) { ["ID"]=> int(5471) ["post_author"]=> string(1) "3" ["post_date"]=> string(19) "2013-12-03 16:25:04" ["post_date_gmt"]=> string(19) "2013-12-03 06:25:04" ["post_content"]=> string(704) "

In a fast and furious fifteen minutes, Mark Dalgleish demystifies Web Components by highlighting how, despite its complex appearance, it's actually made up of a suite of technologies providing features we're already familiar with. Once you understand what web components bring to the table, you'll wonder how we ever lived without them. Make sure you also check out the accompanying blog post for full details.

[iframe width="500" height="281" src="//www.youtube.com/embed/s1PTPZwzQA4?list=UURx1y52pfeMwbuer9Vh2u-A" frameborder="0" Mozallowfullscreen Webkitallowfullscreen allowfullscreen]" ["post_title"]=> string(55) "Web Components - video presentation from Mark Dalgleish" ["post_excerpt"]=> string(0) "" ["post_status"]=> string(7) "publish" ["comment_status"]=> string(4) "open" ["ping_status"]=> string(4) "open" ["post_password"]=> string(0) "" ["post_name"]=> string(53) "web-components-video-presentation-from-mark-dalgleish" ["to_ping"]=> string(0) "" ["pinged"]=> string(0) "" ["post_modified"]=> string(19) "2013-12-05 10:53:33" ["post_modified_gmt"]=> string(19) "2013-12-05 00:53:33" ["post_content_filtered"]=> string(0) "" ["post_parent"]=> int(0) ["guid"]=> string(36) "http://www.webdirections.org/?p=5471" ["menu_order"]=> int(0) ["post_type"]=> string(4) "post" ["post_mime_type"]=> string(0) "" ["comment_count"]=> string(1) "0" ["filter"]=> string(3) "raw" ["post_category"]=> string(1) "0" } [1]=> object(WP_Post)#61 (25) { ["ID"]=> int(5466) ["post_author"]=> string(1) "3" ["post_date"]=> string(19) "2013-12-03 16:17:56" ["post_date_gmt"]=> string(19) "2013-12-03 06:17:56" ["post_content"]=> string(889) "

In the past, validating forms in the client has typically required doing some heavy lifting with JavaScript. But you may not know HTML5 changes all that. Browsers now check that the content of an input match its type (and we've got new types like email, url and number to make that even more useful). But, what you might not know about is the pattern attribute, which lets us use regular expressions directly in HTML to specify what format the user's input should have.

In this session, Chris Lienert looks at some of the common regex patterns you can use to validate user input, coupled with some of the many tricks he's learned to help users complete those forms we all love to hate.

[iframe width="500" height="281" src="//www.youtube.com/embed/Wdg5i01LbG4?rel=0" frameborder="0" Mozallowfullscreen Webkitallowfullscreen allowfullscreen]" ["post_title"]=> string(87) "Validating forms with the HTML5 pattern attribute - video presentation by Chris Lienert" ["post_excerpt"]=> string(0) "" ["post_status"]=> string(7) "publish" ["comment_status"]=> string(4) "open" ["ping_status"]=> string(4) "open" ["post_password"]=> string(0) "" ["post_name"]=> string(85) "validating-forms-with-the-html5-pattern-attribute-video-presentation-by-chris-lienert" ["to_ping"]=> string(0) "" ["pinged"]=> string(0) "" ["post_modified"]=> string(19) "2013-12-03 16:17:56" ["post_modified_gmt"]=> string(19) "2013-12-03 06:17:56" ["post_content_filtered"]=> string(0) "" ["post_parent"]=> int(0) ["guid"]=> string(36) "http://www.webdirections.org/?p=5466" ["menu_order"]=> int(0) ["post_type"]=> string(4) "post" ["post_mime_type"]=> string(0) "" ["comment_count"]=> string(1) "0" ["filter"]=> string(3) "raw" ["post_category"]=> string(1) "0" } [2]=> object(WP_Post)#267 (25) { ["ID"]=> int(5358) ["post_author"]=> string(1) "3" ["post_date"]=> string(19) "2013-11-19 14:15:52" ["post_date_gmt"]=> string(19) "2013-11-19 04:15:52" ["post_content"]=> string(387) "

Right now creating high quality user experiences in HTML5 is very hard, and to get to where we are today we need a huge bundle of hacks and extreme techniques, many of which Andrew Betts covers in the session.

[iframe width="500" height="281" src="http://www.youtube.com/embed/61zGacGIMEA" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen]" ["post_title"]=> string(72) "Making Web Apps as Smooth as Native - video presentation by Andrew Betts" ["post_excerpt"]=> string(0) "" ["post_status"]=> string(7) "publish" ["comment_status"]=> string(4) "open" ["ping_status"]=> string(4) "open" ["post_password"]=> string(0) "" ["post_name"]=> string(70) "making-web-apps-as-smooth-as-native-video-presentation-by-andrew-betts" ["to_ping"]=> string(0) "" ["pinged"]=> string(0) "" ["post_modified"]=> string(19) "2013-11-21 09:48:34" ["post_modified_gmt"]=> string(19) "2013-11-20 23:48:34" ["post_content_filtered"]=> string(0) "" ["post_parent"]=> int(0) ["guid"]=> string(36) "http://www.webdirections.org/?p=5358" ["menu_order"]=> int(0) ["post_type"]=> string(4) "post" ["post_mime_type"]=> string(0) "" ["comment_count"]=> string(1) "0" ["filter"]=> string(3) "raw" ["post_category"]=> string(1) "0" } [3]=> object(WP_Post)#266 (25) { ["ID"]=> int(5057) ["post_author"]=> string(1) "3" ["post_date"]=> string(19) "2013-07-19 15:23:47" ["post_date_gmt"]=> string(19) "2013-07-19 05:23:47" ["post_content"]=> string(11443) "A little while back, Jake Archibald wrote infamously (and anthropomorphically) that the HTML5 ApplicationCache is a "douchebag"[1]. Mindful that this is a word freighted with troubling significance, it is the term he used, so I'll go with it.The Urban Dictionary says the word douchebag
generally refers to a male with a certain combination of obnoxious characteristics related to attitude, social ineptitude, public behavior, or outward presentation.Though the common douchebag thinks he is accepted by the people around him, most of his peers dislike him. He has an inflated sense of self-worth, compounded by a lack of social grace and self-awareness. He behaves inappropriately in public, yet is completely ignorant to how pathetic he appears to others.
I think this is a bit harsh for poor AppCache. To stay with the metapohor, Appcache is doing his best, it's just that he does exactly what you ask him to. Even when no one could possibly mean what you said! In this way, AppCache reminds me of one of my favourite ever comics, Mr Logic, from Viz Magazine (probably NSFW due to its extreme puerility).Mr. Logic's defining characteristic is that he takes everything literally. And as a consequence, he is "a complete pain in the #$%^". He doesn't mean to annoy you, he just doesn't understand nuance, and has no "common sense" (which as my nanna always loved to say is sadly far from common).Mr LogicThis is AppCache to a tee. Ask him to cache the manifest file for your site, so that your site is now preserved in digital amber, never to be updated again, no problem. Why would anyone ever want to do this? Who knows, but he'll do it for you. Removed the manifest attribute from a cached HTML document? Well, AppCache doesn't check changed documents until you change the manifest file, so 'til then, the old cached version of the HTML file, with its link to the manifest still in place will be used. All very logical. But in many ways counter-intuitive.I guess what I'm saying, is the fault, dear reader, lies not in AppCache, but in ourselves. Actually, the fault really lies in the rules that have been taught to AppCache. Some of these are just downright infuriating. And perhaps the most infuriating of these is the following.It starts with the following entirely logical, but deeply unintuitive way in which caching works.
  • A user visits say webdirections.org, and the browser builds an applicationCache using the cache manifest, caching the index.html file, images, CSS files, and JavaScript files
  • Subsequently, we change some of the HTML and CSS at webdirections.org, and update a changed manifest file
  • The user returns to webdirections.org, and their browser immediately uses the cached resources from the previous visit to display the page.
  • The browser only then checks the manifest file to see if it has changed, and as it has, the browser then downloads the changed resources.
It makes perfect sense! We get the cached version immediately, leaving out any network traffic. Super fast page load FTW. Stale page load not so good.But, you say, why don't we not cache the HTML file, but cache all the rest. Well. AppCache has a concept of "master entries". A master entry is an HTML file that includes a manifest attribute in the html element that points to a manifest file (which is the only way to create an HTML5 appcache BTW). Any such HTML file is automatically added to the cache. This makes sense a lot of the time, but not always. In particular, when an HTML document changes frequently, we won't want it cached (as a stale version of the page will most likely be served to the user as we just saw).Is there no way to over-ride this? Well, AppCache has the idea of a NETWORK whitelist, which instructs the appcache to always use the online version of a file. What if we add HTML files we don't want cached to this? Sorry, no dice. HTML files in a master entry stay cached, even when included in the NETWORK whitelist. See what I mean. Poor AppCache didn't make these rules. He's just following them literally. He's not a douchebag, he's a pain in the %^&*, a total "jobs-worth".So we are be stuck. We seem to be able to
  • either add a manifest attribute to the html element of the document, and have the page cached too
  • or have no appcaching at all for that page.
Where we have the front page of a site that changes frequently, we either have the situation that the page will likely be out of date for users who return (because the most recently cached version will always be used), but we get the ability to cache images, CSS, JavaScript and other resources which don't change frequently. Or we can't cache those resources at all.

Updated

The following needs updating, because it is in fact sadly wrong. While no-store foes have an influence on caching, in the case of master entries, rather than simply not caching a master entry, but caching all the other resources in the manifest, we get an error and no resources are cached at all. So, I'm going to turn my technique into a proposal for how AppCache could be made a little less painful. What I suggest below I think is what should happen when the appCache encounters a master entry served with Cache-control: no-store

Original

But, there is a (little known) solution to this. It's in the HTML5 specification, but currently, it's only supported in Internet Explorer (10+, the first version to support AppCache) and Firefox. Hopefully other browsers and devices will start supporting it, because it's a game changer when it comes to AppCache I think.You probably know that (but may not know the details of how) browsers have long used HTTP response headers to decide on how to cache content. The server can also send instruction about whether a resource is cacheable or not.In a nutshell, when a browser requests a resource, the server sends both the content of the resource (for example, a HTML document), and a response header. One of the fields of a response header is Cache-control, which can contain a number of directives, including no-cache, and no-store.
  • no-cache doesn't in fact instruct the browser not to cache the resource, it instructs the browser to always check with the server before using a cached version of the resource (see, it's not just AppCache who can be a pain)
  • no-store means don't cache the resource, and always use the online version.
If you're familiar with AppCache, no-store is the equivalent to the NETWORK section of a cache manifest. Now, how do HTTP headers and AppCache work together? What the HTML5 AppCache spec says about HTTP headers is that they should be ignored for the purposes of AppCache, except no-store. Which means (in theory), we can send an HTML file with the directive Cache-control: no-store, and it won't be cached in the AppCache! Could it be we have a solution to what has been one of AppCaches most infuriating "features".With bated breath I created a test case. On Safari and Chrome, no luck. The HTML file served with no-store is still added to the AppCache. But, with Firefox, and IE10, like Daft Punk, we got lucky. These browsers honour no-store. If I change the HTML document, the next time the page loads, all the cached resources are used from the cache, but the new HTML page displays.So close, and yet so far, I hear you thinking. Because it's not supported across all browsers yet, what good does it do me? Here we'll have to dive a little bit more into AppCache. In browsers that support AppCache, there's a new property, applicationCache, of the window object. This receives various events, including updateReady when the cache has been changed and is now ready to be used. So, we can update a cached master entry as follows.
  1. add an event listener for updateReady
  2. this calls applicationCache.swapCache, which swaps the now stale cache for the fresh one
  3. our event handler now calls window.reload(true) to force a refresh of the page
What's great about our no-store trick is, the cache doesn't need updating, so in browsers which support it, updateReady doesn't fire! So we have a bullet-proof way of making sure frequently changing HTML pages aren't added as master entries to the appcache in browsers which honour no-store, as well as auto-refreshing these pages to ensure the browser uses the most up-to-date version in browsers which don't (yet) honour the no-store directive. Which hopefully makes the AppCache just a little bit less of a pain in the #$%^ to deal with!Again note, sadly this is not what actually happensHere's what does happen when a master entry is served as no-store
  • Chrome and Safari ignore no-store, and build the cache including the master entry
  • Firefox from what I can tell silently fails, and doesn't build a cache at all
  • Internet Explorer (10) fires an error, and doesn't build a cache.
Moral of the story: don't serve HTML with no-store if you want appcache to work!

My upcoming book on HTML5 Offline

I discovered all this, and much more, while researching my upcoming book on HTML5 offline capabilities, not just appcache, but localStorage, the File API, offline events and even HTTP Caching. It's coming soon, so why not sign up to our newsletter to be the first to hear about it, or follow me on twitter (or better still both!).Want to learn more about AppCache in the meantime? Here's an article I wrote a couple of years ago, and this presentation I did at Web Directions Code last year.

Technologies mentioned in this post

People mentioned in this post

References

" ["post_title"]=> string(64) "Appcache, not so much a douchebag as a complete pain in the #$%^" ["post_excerpt"]=> string(0) "" ["post_status"]=> string(7) "publish" ["comment_status"]=> string(4) "open" ["ping_status"]=> string(4) "open" ["post_password"]=> string(0) "" ["post_name"]=> string(58) "appcache-not-so-much-a-douchebag-as-a-complete-pain-in-the" ["to_ping"]=> string(0) "" ["pinged"]=> string(102) "http://www.webdirections.org/sign-up-to-the-newsletter/ http://www.webdirections.org/blog/get-offline/" ["post_modified"]=> string(19) "2013-07-20 11:46:55" ["post_modified_gmt"]=> string(19) "2013-07-20 01:46:55" ["post_content_filtered"]=> string(0) "" ["post_parent"]=> int(0) ["guid"]=> string(36) "http://www.webdirections.org/?p=5057" ["menu_order"]=> int(0) ["post_type"]=> string(4) "post" ["post_mime_type"]=> string(0) "" ["comment_count"]=> string(1) "8" ["filter"]=> string(3) "raw" ["post_category"]=> string(1) "0" } [4]=> object(WP_Post)#265 (25) { ["ID"]=> int(5050) ["post_author"]=> string(1) "3" ["post_date"]=> string(19) "2013-07-18 11:16:57" ["post_date_gmt"]=> string(19) "2013-07-18 01:16:57" ["post_content"]=> string(818) "Chrome Android ImageFollowing Blackberry 10's support for WebRTC, Chrome beta or Android now supports webRTC, as do Firefox, Opera and Chrome for desktop (and Firefox for Android though not as yet Firefox OS it would seem).A very significant milestone for what many consider a game changing technology.Want to get started with webRTC, you might be interested in our recent article, where we built a motion activated security camera in the browser with webRTC." ["post_title"]=> string(37) "WebRTC now in Chrome Beta for Android" ["post_excerpt"]=> string(0) "" ["post_status"]=> string(7) "publish" ["comment_status"]=> string(4) "open" ["ping_status"]=> string(4) "open" ["post_password"]=> string(0) "" ["post_name"]=> string(37) "webrtc-now-in-chrome-beta-for-android" ["to_ping"]=> string(0) "" ["pinged"]=> string(0) "" ["post_modified"]=> string(19) "2013-07-18 11:16:57" ["post_modified_gmt"]=> string(19) "2013-07-18 01:16:57" ["post_content_filtered"]=> string(0) "" ["post_parent"]=> int(0) ["guid"]=> string(36) "http://www.webdirections.org/?p=5050" ["menu_order"]=> int(0) ["post_type"]=> string(4) "post" ["post_mime_type"]=> string(0) "" ["comment_count"]=> string(1) "0" ["filter"]=> string(3) "raw" ["post_category"]=> string(1) "0" } [5]=> object(WP_Post)#264 (25) { ["ID"]=> int(4923) ["post_author"]=> string(1) "3" ["post_date"]=> string(19) "2013-07-08 13:45:42" ["post_date_gmt"]=> string(19) "2013-07-08 03:45:42" ["post_content"]=> string(3208) "

Last week we looked at one of HTML5's syntax quirks, the fact that you don't need to quote attribute values (unless the values contain a space or as is less well known one of a number of other characters). This time, some more about some of the subtle side effects of HTML5's laxer syntax rules.

Let's start with a quiz. Are both of these valid HTML5 documents (that's right, complete documents, not just fragments)? Neither? Only one? Which one? Why?

<!doctype html>
<title></title>
<!doctype html>
<html>
<head></head>
<body></body>
</html>

And the answer is that the first is valid, the second not. Which is very counter-intuitive. Unless you know the rules of HTML5 inside out, it's something you're unlikely to guess. In HTML5 there is precisely one required element. It's not html or head or body. It's title.

Now, does anyone ever actually do this? Try this page out for size.

<!DOCTYPE html>
<html lang=en>
  <meta charset=utf-8>
  <meta name=viewport content="initial-scale=1, minimum-scale=1, width=device-width">
  <title>Error 404 (Not Found)!!1</title>
  <style>…</style>
  <a href=//www.google.com/><img src=//www.google.com/images/errors/logo_sm.gif alt=Google></a>
  <p><b>404.</b> <ins>That’s an error.</ins>
  <p>The requested URL <code>/saef</code> was not found on this server.  <ins>That’s all we know.</ins>

That's Google's 404 page. No head or body elements. (also no pesky closing tag on those ps). I guess if you're serving this millions of times a day, a few bytes count (though I wonder why then use up 22 precious bytes for those two ins) elements?

But in and of itself this isn't all that interesting. What is interesting is this question. If in the style element we had

body p{ 
  color: red
}

Would the paragraphs have red text? The (again counter-intuitive) answer is yes! How so? How can the paragraphs be descended from a body element if we didn't include a body in our markup? Well, that's where HTML5's storied parsing algorithm comes in. Where html or body or head are missing, the parser inserts them into the DOM. Let's take a look at this in action in the Firefox Developer tools

The parser inserts missing elements into the DOM
The parser inserts missing elements into the DOM

Yes, HTML5's parser can make sense of almost any way we as web developers can mangle our markup. But unless you really know what you are doing, and really really need to save a few bytes, why not stick to the slightly more verbose, but far better understood approach.

" ["post_title"]=> string(58) "More HTML5 syntax and parser quirks you may not have known" ["post_excerpt"]=> string(0) "" ["post_status"]=> string(7) "publish" ["comment_status"]=> string(4) "open" ["ping_status"]=> string(4) "open" ["post_password"]=> string(0) "" ["post_name"]=> string(58) "more-html5-syntax-and-parser-quirks-you-may-not-have-known" ["to_ping"]=> string(0) "" ["pinged"]=> string(0) "" ["post_modified"]=> string(19) "2013-07-10 09:49:07" ["post_modified_gmt"]=> string(19) "2013-07-09 23:49:07" ["post_content_filtered"]=> string(0) "" ["post_parent"]=> int(0) ["guid"]=> string(36) "http://www.webdirections.org/?p=4923" ["menu_order"]=> int(0) ["post_type"]=> string(4) "post" ["post_mime_type"]=> string(0) "" ["comment_count"]=> string(2) "27" ["filter"]=> string(3) "raw" ["post_category"]=> string(1) "0" } [6]=> object(WP_Post)#263 (25) { ["ID"]=> int(4907) ["post_author"]=> string(1) "3" ["post_date"]=> string(19) "2013-07-04 15:58:59" ["post_date_gmt"]=> string(19) "2013-07-04 05:58:59" ["post_content"]=> string(2347) "

With HTML5, you don't have to quote attribute values. Until you do.

One of the benefits often touted for HTML5 over XHTML is what I once heard Paul Irish describe as its "loosey goosey" approach to syntax. No longer the strict taskmaster that XHTML was, we can now do all kinds of cool stuff like leave off closing li and p tags, and of course, we no longer need to quote attribute values. Think of the bytes saved! The billions of developer hours saved no longer having to type " or '.

Except.

You can't always leave off quotes from attribute values. Think about an element with two class attribute values.

<p class=important warning>

Here the browser actually see two attributes, class=important and a boolean attribute warning (which it doesn't understand, but that's not a problem, making up your own attribute names is what all the kids are doing these days (I'm looking at you Angular!))

So, we need to quote attributes values when they include spaces. But that's not all. Unquoted attribute values must also not contain any of these characters:

", ', =, >, <, or `. Sure, you can have %, or # or £, but no backticks please!

If it does, then quote you must. Think about all sorts of URLs for APIs, or into CMS content, or to blog posts. A = is very likely to crop up in these URLs. So, why not simply quote all attribute values? One basic rule that will never get you into trouble, and cost you maybe a few dozen bytes a page at most.

BTW, the same rule applies to CSS values that take urls. We only need to use quotes around the URL value when it includes one of the same characters. But why not always again use quotes? Simple pattern, always works. And, the same applies to the value of attribute selectors. a[attr="attrvalue"] will always be correct. a[attr=attrvalue] won't be if attrvalue contains spaces or one of our magic characters.

You could try to remember all these rules - go for it! But sometimes it just pays to be strict.

" ["post_title"]=> string(59) "Five reasons why you should quote attribute values in HTML5" ["post_excerpt"]=> string(0) "" ["post_status"]=> string(7) "publish" ["comment_status"]=> string(4) "open" ["ping_status"]=> string(4) "open" ["post_password"]=> string(0) "" ["post_name"]=> string(59) "five-reasons-why-you-should-quote-attribute-values-in-html5" ["to_ping"]=> string(0) "" ["pinged"]=> string(0) "" ["post_modified"]=> string(19) "2013-07-04 15:58:59" ["post_modified_gmt"]=> string(19) "2013-07-04 05:58:59" ["post_content_filtered"]=> string(0) "" ["post_parent"]=> int(0) ["guid"]=> string(36) "http://www.webdirections.org/?p=4907" ["menu_order"]=> int(0) ["post_type"]=> string(4) "post" ["post_mime_type"]=> string(0) "" ["comment_count"]=> string(2) "32" ["filter"]=> string(3) "raw" ["post_category"]=> string(1) "0" } [7]=> object(WP_Post)#262 (25) { ["ID"]=> int(4884) ["post_author"]=> string(1) "3" ["post_date"]=> string(19) "2013-07-02 13:42:52" ["post_date_gmt"]=> string(19) "2013-07-02 03:42:52" ["post_content"]=> string(27307) "

A couple of weeks ago we started a series on how you might implement some of the more notable design effects in iOS 7 using purely web technologies. In the meantime, it's been noted elsewhere that this may be difficult and perhaps impossible to do. I'm here today to tell you otherwise! Well, at the least the impossible part.

Today we are going to look at one of the features that got some attention, the use of parallax on the homescreen to create a sense of depth This is one of the words that Apple used to describe their new, supposedly "flat" design.

If you've not seen this in action, Gizmodo took Apple's video and made an animated GIF version, which you can see below.

animated gif of the parallax effect on the homescreen
Gizmodo

It got me thinking, how did they do that? How easy would it be to replicate using web technologies?

Before we jump in and build it, you can take a look at the finished product on a smartphone, or emulated in your browser to get a sense of what we're going to be doing.

We've all seen parallax effects before. They're a staple of 2D, and "2.5D" games, to add the perception of distance between objects. For the last couple of years we've also seen the use, and abuse, of parallax and scrolling in web page design.

So, what is going on to create what appears at a glance to be a 3rd dimension? Well I'll let you in on a little secret that anyone who has installed the iOS 7 beta will have already noticed. The effect is particularly impressive when viewing a 2D rendering (such as a video) of the effect. When you see the same effect on a device, and then watch a video of the effect on the device, I think you'll find the video more compelling.

What is parallax?

Look out the window. Objects at different distances move at different relative speeds. The closer an object, the more quickly it appears to be moving, and the further away it is, the more slowly it appears to be moving.

Documentary film makers, who often have only photographs or paintings to use as their primary visual material, commonly make use of this to trick our eyes into seeing a 3rd dimension. It's called "the Kid Stays in the Picture" effect. It tricks our brain that we are looking at a 3D scene, by using different relative motions.

In the iOS 7 homescreen situation, we have two levels of depth. The surface of the screen, and the background image. If you pay attention to the animated version, you'll see that the icons don't move relative to the surface of the screen. The effect is created purely by moving the background image relative to the icons. Notice how as we tilt the phone from right to left (on the screen) the background image moves toward the right, and as the phone tilts from left to right, the image moves back to the left. Why does this create a sense of depth? For the moment, to keep things simple let's just worry about rotation around a line running from the top to the bottom of the screen through its middle as the device is facing toward us. That is, when we tilte the phone left and right.

Imagine we were looking down on the scene from above

looking down on the scene from above
looking down on the scene

The vertical arrow is the line of sight. Now, let's rotate the phone to the left

rotating the phone to the left
looking down on the scene, having rotated the phone to the left

I cheated a bit here, to make the maths a little bit simpler, but the idea is more or less the same. Instead of the device rotating, I've moved the observer, but their line of site is still the same - directly between the two icons in the middle of the screen. So, the icons don't appear to move relative to the screen, but the background figures do. But just how far are the figures apparently shifted?

the original and new lines of sight make a right triangle
the original and new lines of sight make a right triangle

I'm making the observation that the original, and adjusted lines of sight of the viewer make a right-angled triangle. Which is excellent, because the trigonometry (don't be put off!) of right-angled triangle is simpler than arbitrary triangles.

the trigonometry of the triangle created by the two lines of sight
the trigonometry of the triangle created by the two lines of sight

OK, so if your high school maths is a little rusty (don't worry, I have a degree in mathematics and I had to look this up!) here's what we have.

  • We have the original line of sight (we've labelled that a, which you might remember as being the adjacent side.
  • We have our new line of sight, labelled h for hypotenuse
  • we have the angle between the old and new lines of sight, θ (pronounced theta, for some reason, angles are usually labelled using Greek letters).
  • We have the distance at right angles from the hypotenuse to the adjacent side, labelled o for opposite (because it is the side opposite the angle we know, θ)

And we have enough information to calculate o, should we know the length of a, using our high school trig

o = a*tan(θ)

We know θ, it's the angle we've rotated the screen (and we'll see in a moment how we'll use the deviceOrientation event to get this angle as it changes). But how do we know a? Well, here's the cool part, we just make it up. The larger the value of a, the further 'away' the background figures will appear to be (so the larger o will be.) In particular what this means is the relative movement of the background figures behind the icons is not linear, but goes something like this, where the background is 50px away

degreesapparent movement (px)
00
54
109
1513
2018
2523
3029
3535
4042
4550
5060
5571
6087
65107
70137
75187
80284
85572
90

Note how the movement left or right increases dramatically as we get closer to θ = 90 degrees. Of course it can never be 90 degrees.

In short, the more we rotate the device, the more the background image appears to move.

Creating the effect

So, now we have a basic model for how parallax works, how can we use this to emulate the parallax effect? Here's my idea

  • we'll have an element that emulates the homescreen of the device
  • the homescreen element contains the application icons
  • we'll have a background image for that element, like the one in Apple's animated example.

Now we have our basic content

  • when the device rotates to the right, we calculate how far to the left our background image should move, which will change depending on how far "away" we want the background to be
  • when the device rotates to the left, we calculate how far to the right the background should move
  • we then use background-position to move the background image relative to the element.

There are other ways we could do this, with their own advantages. We could have the background as a separate img element, then use CSS3 translate3D to move this element to the left and right. This would have the advantage of enabling the device's GPU to take care of moving the background. But we'll stick to background-position, as it's the simplest approach.

So, here's our basic HTML

<section id="homescreen">
		<figure id="app1">
			<img src="images/app1.png">
			<figcaption>App 1</figcaption>	
		</figure>

	<figure id="app2">
			<img src="images/app2.png">
			<figcaption>App 2</figcaption>	
		</figure>

	<figure id="app3">
			<img src="images/app3.png">
			<figcaption>App 3</figcaption>	
		</figure>

	<!-- and so on -->		
	</section>

and some very basic style

#homescreen {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
background-image: url('images/wds12.jpg'); 
background-repeat: no-repeat;
}

#homescreen figure {
width: 64px;
text-align: center;
float: left;
margin: 20px;
text-shadow: 0 1px 0 #555; }

#homescreen img {
width: 100%;
border-radius: 10px;
box-shadow: 0 4px 4px -2px rgba(0, 0, 0, .6);
 }

Which gives use something like this.

the homescreen
the homescreen

Yes, not particularly interesting, yet. Now let's think about moving the background image.

By default, a background image is positioned with its top left hand corner in the element's top left hand corner. But this isn't what we'll want, because as soon as we rotate to the left, the image moves to the right, and so we'll see "through" the element on the left of the background image like so.

the homescreen with image moved to right
the homescreen with image moved to right

So we'll need to make sure that our image is wider than our element, and positioned not in the top left hand corner. We could use the CSS3 property background-size to achieve the first, but we need to be careful. Suppose we decided to make the width of any background image 150% the width of the element. We'd use background-size: 150% to do this, but this then scales the height of the element to maintain the image's proportions. For an image that is inherently narrower than the element's current size, then the height will increase. But if the image is inherently wider than 150% of the width of the element in pixels, then the height of the image will decrease, and we may end up with this situation.

the background image is scaled to 150% of the width of the element, but as it is wider than this inherently, the height it reduced.
the background image is scaled to 150% of the width of the element, but as it is wider than this inherently, the height is reduced.

Better to have an image that will in all likelihood be taller and wider than the element's width and height (yes, in a responsive world, this will present its own challenges).

The second part is a bit more straightforward. Surely, we'll just use background-position: center? Sadly, not quite so simple. Because we'll be changing the background-position to achieve the effect. So, what we do is position the background image using JavaScript and the DOM, so that its top is half the difference between its intrinsic height and the current height of the homescreen element above the top of the element, and similarly, its left is half the difference between its width height and the current width of the homescreen element to the left of the element. Essentially, the center of the image will be in the center of the element.

positioning the background image.
Positioning the background image.

We'll do this by adjusting the background-position of the element once the page has loaded (as is often the case, this is the most complicated part of the process, even though it's only peripheral.)

function setupBackgroundImage(element) {

	//set up the background image for the element
	//call this when the page loads
		
	var imgURL = window.getComputedStyle(element).backgroundImage 
	//get the current background-image URL
		
	//bg image format is url(' + url + ') so we strip the url() part
	imgURL = imgURL.replace(/"/g,"").replace(/url\(|\)$/ig, "");
	
	//now we make a new image element and set this as its source
	var theImage = new Image();
	theImage.src = imgURL;
	
	//we'll set an onload listener, so that when the image loads, we position the background image of the element
	
	theImage.onload = function() {
		positionBackgroundImage(element, this.width, this.height)		
	}

}

function positionBackgroundImage(element, imageWidth, imageHeight) {
	//this is called when a backgroundImage loads
	
	var elRect = element.getBoundingClientRect();
	xOffset = -1 * (imageWidth - elRect.width)/2
	yOffset = -1 * (imageHeight - elRect.height)/2
	//these are global variables as we want to remember the offsets for later
	//ideally  we'd not use global vars, but done like this for simplicity
	
	element.style.backgroundPosition = xOffset + "px " + yOffset + "px"
}

Now we've set up our elements, our homescreen background image, and we've worked out our algorithm, we're ready to go.

Adjusting the background image

OK, at this point, we'll pretend we already know the current rotation of the device (we'll cover how we get that next). Let's assume that each time the device changes its orientation we get an event. Which in fact is exactly what happens. We'll create an event handler for this event. As we're responding to a change in the orientation, we'll call this 'orientationChanged'. Here's what this will need to do (again we'll concentrate on just the rotation around the Y axis of the device to keep things simple)

  • calculate the tan of the rotation around the Y axis (in radians, not degrees) (this was θ in our earlier discussion). More on radians in the notes
  • calculate the relative movement of the background image (a*tan(θ))
  • adjust for the xOffset we calculated earlier based on the width of the background image and the element
  • set the background-position of the element to this value

And here's that in JavaScript

function orientationChanged (xOrientation, yOrientation) {
	
	var rotYTan = Math.tan(yOrientation*(Math.PI/180))
	//calculate the tan of the rotation around the Y axis
	//Math.tan takes radians, not degrees as the argument
	 
	var backgroundDistance = 50 
	//set the distance of the background from the foreground
	//the smaller, the 'closer' an object appears
	
	var xImagePosition = (-1 * rotYTan * backgroundDistance) + xOffset + "px"
	//calculate the distance to shift the background image horizontally
	//the X and Y seem swapped, but X in device rotation terms is around a line through the middle of  of the screen from left to right, so its correct
	
	homescreen.style.backgroundPosition = xImagePosition + " " + 0;
	//set the backgroundimage position to  xImagePosition	
}

So, now we are moving the background image left or right depending on the rotation of the device. But how well does this work? Well, you can test it out yourself. Here's an emulation, which uses CSS 3D transforms, as well as a version you can run directly in a device. What do you think? In the emulated version, you might think the 3D effect is simply coming from the use of CSS 3D, but if you set the distance to zero, and then rotate the device, you'll see that there is no parallax effect. The greater the distance you set, the more pronounced the effect.

The main event

But so far, we've not discussed how we actually get this mystical orientation information. As we mentioned briefly we'll be using the deviceOrientation event widely supported in mobile devices in particular.

I covered DeviceMotion and DeviceOrientation in some detail recently when I built a motion activated security camera in the browser, so we'll not go into the details of DeviceOrientation here. In short though

  • alpha is the rotation around the z-axis (an imaginary line coming directly out of the screen). Positive alpha is rotated to the left, negative alpha is rotate to the right. This seems counter intuitive, but our frame of reference is looking upwards, so to the left is clockwise in this frame of reference, and clockwise is positive, anti-clockwise negative.
  • beta is rotation around the x-axis, a line left to right across the device when it is laid flat on its back. Positive beta is when the device is tilted away from you, from 0 degrees to 180 degrees (screen facing downwards). Negative alpha is when the device is tilted toward you (again, from 0 degress to -180 degrees, which is facing downward)
  • gamma is rotation around the y-axis, a line through the middle of the device away from the user. Positive (from 0 to 180 degrees) is tilted to the left. Negative, 0 to -180 degrees, is tilted to right

Which is all a lot easier to understand with a picture.

the x, z, and z axis, with alpha, beta and gamma rotation
the x, z, and z axis, with alpha, beta and gamma rotation. Device probably doesn't actually support deviceOrientation.

Here's how we'll use this information

  1. we'll add an event listener for devicemotion events to the Window
  2. this function will receive an event, which includes information about the current rotation of the device around its x, y and z axes
  3. We'll use this to determine the distance our background image should moved to achieve the parallax effect
  4. We'll then move our image based on this calculation

Here's our event handler, which is almost identical to the code above, just adapted to take the orientation event as its argument.

function orientationChanged (orientationEvent) {
	
	var gamma = orientationEven.gamma;
	//get the rotation around the y-axis from the orientation event
	
	var tanOfGamma = Math.tan(gamma*(Math.PI/180))
	//calculate the tan of the rotation around the Y axis (gamma)
	//Math.tan takes radians, not degrees as the argument
	 
	var backgroundDistance = 50 
	//set the distance of the background from the foreground
	//the smaller, the 'closer' an object appears
	
	var xImagePosition = (-1 * tanOfGamma * backgroundDistance) + xOffset + "px"
	//calculate the distance to shift the background image horizontally
	
	homescreen.style.backgroundPosition = xImagePosition + " " + 0;
	//set the backgroundimage position to  xImagePosition 0
}

What the X?

Ok, so there's a reason we've still only worried about movement left to right. When you look at a screen, the neutral position in terms of rotation around the y axis (that is, tilted to left or right) is clearly with the screen perpendicular to the user's line of sight. But, what's the neutral position for the tilt forward and backwards? Lying on its back? Probably not. Perpendicular to the surface of the earth? Also probably not. When you hold a phone or tablet, it's likely to be somewhere between these two.

To simplify matters, let's say that the user will typically hold a device at around 45 degrees. So, we'll make this our "neutral" position for the parallax effect. Which means, we'll subtract 45 degrees from the current rotation when calculating the position of the background image up and down.

function orientationChanged (orientationEvent) {
	
	var beta = orientationEvent.beta;
	var gamma = orientationEvent.gamma;
	//get the rotation around the x and y axes from the orientation event
	
	var tanOfGamma = Math.tan(gamma*(Math.PI/180))
	var tanOfBeta = Math.tan((beta -45)*(Math.PI/180))
	//calculate the tan of the rotation around the X and Y axes
	//we treat beta = 45 degrees as neutral
	//Math.tan takes radians, not degrees, as the argument
	
	var backgroundDistance = 50 
	//set the distance of the background from the foreground
	//the smaller, the 'closer' an object appears
	
	var xImagePosition = (-1 * tanOfGamma * backgroundDistance) + xOffset + "px"
	var yImagePosition = (tanOfBeta * backgroundDistance) + yOffset + "px"
	//calculate the distance to shift the background image horizontally
	
	homescreen.style.backgroundPosition = xImagePosition + " " + yImagePosition;
	//set the backgroundimage position to  xImagePosition yImagePosition
}

Dis-orientation

What's also interesting is that if we change the orientation of the screen, from landscape to portrait, the beta and gamma values from the orientation event are still relative to the device. So, we need to now take into account whether the screen has been flipped (maybe even upside down) before doing our calculations.

First, we need to know what the current screen orientation is. We do this with the screenOrientation property of the window. This is the current rotation of the screen, where 90 degrees is rotated to the right, 180 degrees is turned upside down, and -90 degrees is rotated to the left.

screenOrientation values
screenOrientation values. Cell Phone designed by Marwa Boukarim from The Noun Project

Let's think about each of these three 'new' possible states in turn.

When turned upside down (screenOrientation === 180), we'll reverse the beta and gamma values, by multiplying them by -1. Effectively, we're treating up as down, and down as up, left as right, and right as left.

if (screenOrientation === 180) {
	beta = -1 * orientationEvent.beta
	gamma = -1 * orientationEvent.gamma
}

When rotated left, screenOrientation === -90, we'll swap gamma for beta, and the reverse of beta (-1 * beta) for gamma. Essentially, swapping left and right for forward and back, back for right, and forward for left.

if (screenOrientation === -90) {
	beta = orientationEvent.gamma
	gamma = -1 * orientationEvent.beta
}

Lastly, when the screen is rotated to the right (screenOrientation === 90), we'll do the opposite. So we swap left for forward, right for backward, forward for left, and backwards for right.

if (screenOrientation === 90) {
	beta = -1 * orientationEvent.gamma
	gamma = orientationEvent.beta
}

Then we continue as before, and now regardless of the screen's orientation, we still have our parallax effect. We've actually gone one step further than the real iOS homescreen, at least on the iPhone, as on the iPhone device rotations don't affect the orientation of the homescreen.

Getting the Code

So, very little code really to achieve the effect, particularly after we've set up our background image. If you'd like to grab the code, it's all up on Github. And here's the finished product if you want to visit it in your tablet or phone of choice. Provided they support DeviceOrientation events, the effect should work. Enjoy!

Technologies covered in this post

Browser Support via Can I Use

Notes

In school, you most likely did trigonometry and geometry with angles in degrees. Grown up math is typically done in radians, where 2π radians is 360 degrees. Since device orientation gives us rotation in degrees, we covert to radians by multiplying the number of degrees we have by π and then dividing by 180.

" ["post_title"]=> string(51) "The iOS 7 homescreen parallax effect in the browser" ["post_excerpt"]=> string(0) "" ["post_status"]=> string(7) "publish" ["comment_status"]=> string(4) "open" ["ping_status"]=> string(4) "open" ["post_password"]=> string(0) "" ["post_name"]=> string(51) "the-ios-7-homescreen-parallax-effect-in-the-browser" ["to_ping"]=> string(0) "" ["pinged"]=> string(118) " http://www.webdirections.org/blog/build-a-motion-activated-security-camera-with-webrtc-canvas-and-device-orientation/" ["post_modified"]=> string(19) "2013-07-04 15:28:19" ["post_modified_gmt"]=> string(19) "2013-07-04 05:28:19" ["post_content_filtered"]=> string(0) "" ["post_parent"]=> int(0) ["guid"]=> string(36) "http://www.webdirections.org/?p=4884" ["menu_order"]=> int(0) ["post_type"]=> string(4) "post" ["post_mime_type"]=> string(0) "" ["comment_count"]=> string(2) "14" ["filter"]=> string(3) "raw" ["post_category"]=> string(1) "0" } [8]=> object(WP_Post)#62 (25) { ["ID"]=> int(4745) ["post_author"]=> string(1) "3" ["post_date"]=> string(19) "2013-06-14 11:40:38" ["post_date_gmt"]=> string(19) "2013-06-14 01:40:38" ["post_content"]=> string(3169) "Nintendo Web Framework LogoFor most of the history of what might loosely be termed computer games, dedicated consoles (and handheld gaming devices) ruled the roost. And none loomed larger on the landscape than Nintendo, with combined sales of hundreds of millions of units.The dominance of this handful of device makers (essentially Nintendo, Sony and Microsoft) meant that developing games for wide distribution on these devices was expensive, and tightly controlled by the device manufacturers. And games generally cost $50, $100 or even more.The success of smartphone and tablet platforms has impacted these traditional dedicated devices,and their entire ecosystem tremendously. Sales of consoles and gaming handhelds are down dramatically (down 27% in the US in 2012, year on year), as are sales of games (down 23% for the year in 2012).In response, Nintendo recently announced the Nintendo Web Framework
a development environment based on WebKit technologies, supporting application development on the Wii U system using HTML5, JavaScript, and CSS. It also supports the Wii U GamePad controller, Wii Remote controllers, and JavaScript extensions such as video playback. With the Nintendo Web Framework, development times will be reduced and Wii U applications can be easily developed using common Web technologies
We can only hope that games built with the framework will also be able to be run (legally and technically) on other platforms, at least within reason.Regardless, developing games for this once exclusive platform promises to become a whole lot easier, and more democratic. And if you think games built with HTML5 aren't a reality, the entire UI for SimCity is built with web technologiesWant to try it out? Sadly, it's still not available. But you can sign up to express your interest here.

More on games and the Wii U

The Wii U web browser's HTML5 gaming capabilities from HTML5 Game Developers Lost Decade Games

People mentioned in this post

Scott Clarke (@maxisscott): Javascript/UX developer for the SimCity UX team

Companies mentioned in this post

" ["post_title"]=> string(20) "Wii Games with HTML5" ["post_excerpt"]=> string(0) "" ["post_status"]=> string(7) "publish" ["comment_status"]=> string(4) "open" ["ping_status"]=> string(4) "open" ["post_password"]=> string(0) "" ["post_name"]=> string(20) "wii-games-with-html5" ["to_ping"]=> string(0) "" ["pinged"]=> string(0) "" ["post_modified"]=> string(19) "2013-06-14 11:40:38" ["post_modified_gmt"]=> string(19) "2013-06-14 01:40:38" ["post_content_filtered"]=> string(0) "" ["post_parent"]=> int(0) ["guid"]=> string(36) "http://www.webdirections.org/?p=4745" ["menu_order"]=> int(0) ["post_type"]=> string(4) "post" ["post_mime_type"]=> string(0) "" ["comment_count"]=> string(1) "1" ["filter"]=> string(3) "raw" ["post_category"]=> string(1) "0" } [9]=> object(WP_Post)#261 (25) { ["ID"]=> int(4739) ["post_author"]=> string(1) "3" ["post_date"]=> string(19) "2013-06-13 14:02:23" ["post_date_gmt"]=> string(19) "2013-06-13 04:02:23" ["post_content"]=> string(4869) "Remember the X in XML, and XHTML? It of course stands for extensible, the idea that these languages allow for their users to build upon them, rather than waiting for some standards organisation to add new features.With HTML5, extensibility of the markup language pretty much went out the window, despite the criticisms of many (including it must be said, me).But extensibility is deeper than simply new language elements. As the web platform becomes increasingly sophisticated and powerful, it has also increasingly been seen as a competitor to "native" platforms such as iOS and Android. And where these platforms iterate quickly, with major new versions in the timeframe of each year or even more frequently, the web is seen to iterate far less quickly. We as developers need to wait not just for new browser versions (which in the case of desktop versions of Chrome and Firefox at least, is in the order of weeks), but whole new features of the DOM, CSS, and HTML, which typically is in the order of years.Many have been frustrated with this pace of change, anxious that it puts the web at a disadvantage over the commercial platforms with far faster evolution. But the suggestions as to what might be done about it (for example, that the web should have "a single source repository and a good owner to drive it") have not been on the whole realistic, or even really solutions to the challenge at all.Now Yehuda Katz, Alex Russell, and numerous other high profile web developers, browser developers and specification authors have suggested a new way forward, summarised in The Extensible Web Manifesto.In essence, the goal is to have new browser features implemented at a lower level, as DOM APIs, accessible through JavaScript (these might also be described as "imperative" features), as opposed to more high level, declarative features accessible at the level of the markup language.Katz describes the situation of offline web apps, and how the approach to building a high level, "magical", declarative feature, AppCache, went wrong, and how developing this functionality at a lower level might have avoided the problem, by empowering developers to build the solution they needed for their use cases.
We could have built offline support as a new JavaScript capability, with the manifest feature built on top of that capability. Then, when the manifest failed Facebook (and lanyrd, and the Financial Times), they could have dropped down into JavaScript and written something that worked for them.Instead of placing our faith in central planning, we should let the ecosystem of web developers build the features they need, on top of low-level capabilities exposed efficiently and securely by the browser.
Will this be the approach to developing new web features we see more of? With members of the W3C's Technical Architecture Group, or TAG, such as Alex Russell, Anne van Kesteren and Marcos Caceres firmly on board, along with the inventor of JavaScript, Brendan Eich, and numerous influential W3C and Browser vendor figures among others, I think it's a fair chance.But with an approach that at least superficially seems at odds with HTML's self appointed benevolent dictator for life Ian Hickson's, where does that leave the WHATWG in all of this?

Further Reading

People mentioned in this article

" ["post_title"]=> string(25) "Towards an extensible web" ["post_excerpt"]=> string(0) "" ["post_status"]=> string(7) "publish" ["comment_status"]=> string(4) "open" ["ping_status"]=> string(4) "open" ["post_password"]=> string(0) "" ["post_name"]=> string(25) "towards-an-extensible-web" ["to_ping"]=> string(0) "" ["pinged"]=> string(0) "" ["post_modified"]=> string(19) "2013-06-13 14:12:29" ["post_modified_gmt"]=> string(19) "2013-06-13 04:12:29" ["post_content_filtered"]=> string(0) "" ["post_parent"]=> int(0) ["guid"]=> string(36) "http://www.webdirections.org/?p=4739" ["menu_order"]=> int(0) ["post_type"]=> string(4) "post" ["post_mime_type"]=> string(0) "" ["comment_count"]=> string(1) "9" ["filter"]=> string(3) "raw" ["post_category"]=> string(1) "0" } [10]=> object(WP_Post)#260 (25) { ["ID"]=> int(4731) ["post_author"]=> string(1) "2" ["post_date"]=> string(19) "2013-06-12 15:17:15" ["post_date_gmt"]=> string(19) "2013-06-12 05:17:15" ["post_content"]=> string(623) "

As much as they affect JavaScript, state, event handling, and default browser behaviour also impact HTML and CSS in the choices we make, optimizations we can take advantage of, and the architecture of our applications as a whole.

Like what you see? Want a piece of the action next time around? Then get along to Web Directions South in Sydney October 24 and 25 2013.

" ["post_title"]=> string(71) "HTML, CSS and the Clientside App - Video Presentation from Garann Means" ["post_excerpt"]=> string(0) "" ["post_status"]=> string(7) "publish" ["comment_status"]=> string(4) "open" ["ping_status"]=> string(4) "open" ["post_password"]=> string(0) "" ["post_name"]=> string(68) "html-css-and-the-clientside-app-video-presentation-from-garann-means" ["to_ping"]=> string(0) "" ["pinged"]=> string(0) "" ["post_modified"]=> string(19) "2013-06-12 15:17:15" ["post_modified_gmt"]=> string(19) "2013-06-12 05:17:15" ["post_content_filtered"]=> string(0) "" ["post_parent"]=> int(0) ["guid"]=> string(36) "http://www.webdirections.org/?p=4731" ["menu_order"]=> int(0) ["post_type"]=> string(4) "post" ["post_mime_type"]=> string(0) "" ["comment_count"]=> string(1) "1" ["filter"]=> string(3) "raw" ["post_category"]=> string(1) "0" } [11]=> object(WP_Post)#258 (25) { ["ID"]=> int(4693) ["post_author"]=> string(1) "3" ["post_date"]=> string(19) "2013-06-07 11:43:40" ["post_date_gmt"]=> string(19) "2013-06-07 01:43:40" ["post_content"]=> string(17071) "

As a web developer, you've probably seen emerging HTML5 technologies and APIs like DeviceOrientation and WebRTC (Web Real Time Communications), and thought "wow they look cool, but they are only for hard core gaming, video conferencing, and other such stuff, not for my every day development". I'm firmly convinced that taking advantage of these capabilities is going to open up fantastic potential for developers, both for existing web sites, as well as entirely new web experiences. In this article, I want to talk about the latter.

When we first moved into the Web Directions office, we had an old iMac (I mean old) set up as a motion activated security camera. One of the guys who used to share the office with us had built a very simple app that when it detected movement (I'm assuming by analysing images) it sent a photo to a specified email address. Sadly, the Mac and app went when the guy moved out. I say sadly, because a few months back we could really have done with this to help catch whoever came by one night at 3am, smashed in our door, and took several devices.

But then it occurred to me this is something we can build in the browser. All we'd need to do was

  1. Detect motion (with the DeviceMotion API (though it's a bit more complex than this in practice as we'll see in a moment)
  2. Capture an image using WebRTC and the HTML5 canvas
  3. Send the image via email (we won't cover that today, as it is really more a server side issue, but there's all kinds of ways you could do it) to ourselves.

So, let's get started. We'll begin by detecting motion.

Detecting motion

You're probably thinking, there's an HTML API for this, DeviceMotion. Which is exactly what I thought. The problem is, while well supported in mobile and tablet browsers (these devices almost universally have gyroscopes for detecting their orientation in 3D space, and accelerometers for detecting their acceleration in 3D as well) it's not supported in any desktop browser. But, there is a related API, DeviceOrientation which reports the angle at which the device is in 3 dimensions, and which is supported in Chrome, when the laptop it is running on has the sensors to provide this data (I know that the MacBook Pro, but not Air support DeviceOrientation). DeviceMotion and DeviceOrientation work similarly. They both are events sent to the window object when something changes about the device. We can provide event listeners for these events, then respond to the data they provide.

Let's create event handlers for each of these kinds of event

if (window.DeviceMotionEvent) {
  window.addEventListener('devicemotion', motionHandler, false)
}

else if (window.DeviceOrientationEvent) {
  window.addEventListener('deviceorientation', orientationHandler, false)
}

For each type of event, we make sure that the window object supports the event type, and if it does we add an event listener to the window for the type of event.

Ok, so now our Window can receive these events, let's look at what information we get from each event, and how we can detect whether the device is in motion.

As mentioned, the most logical way to do so is via DeviceMotion, but here's the complication. An ideal device for using as a security camera is an old laptop. It's powered, so the battery won't go flat, and on tablets, only Chrome for Android supports getUserMedia, for operating the device's video camera. But, we can use DeviceOrientation to detect motion as we saw on some laptops in Chrome. Let's do that first, then quickly look at how we can do the same thing for devices which support DeviceMotion events.

Here's our handler for DeviceOrientation events.

function orientationHandler (orientationData){
  var today = new Date();

  if((today.getTime() - lastMotionEvent) > motionInterval){	
    checkMotionUsingOrientation(orientationData)
    lastMotionEvent = today.getTime()
  }
}

and similarly, our handler for DeviceMotion events

motionHandler: function (motionData){
  var today = new Date();

  if((today.getTime() - lastMotionEvent) > motionInterval){	
    checkMotionUsingMotion(motionData)
    lastMotionEvent = today.getTime()
  }
}

Because DeviceMotion and DeviceOrientation events fire many many times a second, if we were to respond to every single such event, we'd have a very warm laptop, and on battery powered devices, much shorter battery life. So, here we check the current time, and only if the time since we last responded to this event is greater than some interval we respond to the event. Checking for movement a few times every second should be more than adequate.

The event listeners receive deviceOrientation events, with data about the event, including information about the device's orientation around 3 axes—alpha, beta and gamma.

  • alpha is the device's rotation around the z axis, an imaginary line extending out vertically from the middle of the device when it is lying flat on its back. In theory, alpha=0 is facing east, 90 is facing south, 180 is facing west, and 270 is facing north, but due to practical reasons, alpha is really only accurate for relative motions, not absolute directions, and so for example can't be used to create a compass.
  • beta measures the rotation around the x axis, a line horizontally through the device from left to right. 0 is when the device is flat, positive values are the number of degrees that the device is tilted forward, and negative values, the number of degrees it's tilted backwards
  • gamma measures the device's rotation around the y axis, a line horizontally along the plane of the devices keyboard (or screen). Positive values at the number of degrees it's tilted to the right, and negative values, the number of degrees it's tilted to the left
the device orientation axes
Device Orientation axes, laptop image ©umurgdk

Responding to the event

So, here's how we'll respond to the the event, and determine whether the device has moved.

function checkMotionUsingOrientation(orientationData){
  //detect motion using change in orientation
   
  var threshold = .7; //sensitivity, the lower the more sensitive
  var inMotion = false;
  
  var betaChange = orientationData.beta - lastBeta //change in beta since last orientation event
  var gammaChange = orientationData.gamma - lastGamma //change in gamma since last orientation event
      
  inMotion = (Math.abs(orientationData.beta - lastBeta) >= threshold ) || (Math.abs(orientationData.gamma - lastGamma) >= threshold)
  //if the change is greater than the threshold in either beta or gamma, we've moved 

  if (inMotion) {
    //do something because it is in motion
    }
  }
  
  lastBeta = orientationData.beta;
  lastGamma = orientationData.gamma;
  //now we remember the most recent beta and gamma readings for comparing the next time

The orientationData argument is our deviceOrientation event. Along with the sorts of information we'd expect from any event, it has 3 properties, alpha, beta and gamma, with no prizes for guessing what these contain.

What our function does is gets the beta and gamma values from the event, and subtracts the difference from the last time we measured these. If either of these differs by more than some threshold we've set (in this case a little under 1 degree) then we've detected a movement. We finish by storing the most recent beta and gamma values. We've not bothered with alpha values, because Chrome, at present the only browser to report these values on the desktop, doesn't report alpha values, and because moving a device only around one axis is extremely difficult, so if there's movement around beta or gamma, then that's good enough for our purposes. Essentially when the device is lying flat on its back, anyone walking in the vicinity will trigger this event.

How about doing the same thing when device motion events are supported? This time, instead of reporting the devices orientation in space, we get information about its acceleration in each of the same axes, x, y and z.

  • motionData.acceleration.x is the acceleration of the device, in metres per second per second (ms^2), to the right (relative to the device) (so negative values are acceleration to the left)
  • motionData.acceleration.y is the acceleration of the device, in metres per second per second (ms^2), forward (relative to the device) (negative values are acceleration "backwards")
  • motionData.acceleration.z is the acceleration of the device, in metres per second per second (ms^2), upwards (relative to the device) (negative values are downwards)

Here's how we'd use this to detect motion.

checkMotionUsingMotion: function(motionData){
  //agorithm courtesy
  //http://stackoverflow.com/questions/8310250/how-to-count-steps-using-an-accelerometer

  var threshold = 0.2;
  var inMotion = false;
  
  var acX = motionData.acceleration.x;
  var acY = motionData.acceleration.y;
  var acZ = motionData.acceleration.z;
  
  if (Math.abs(acX) > threshold) {
    inMotion = true
  }
  
  if (Math.abs(acY) > threshold) {
    inMotion = true
  }  
  
  if (Math.abs(acZ) > threshold) {
      inMotion = true
  }

  if (inMotion) {
    //do something because it is in motion

  }
}

Here we take the acceleration in each axis, and if any of these is greater than a threshold amount (to ensure we don't get false positives) then we're in motion. You can see it's a little simpler than using deviceOrientation, as we don't need to calculateany change.

Taking the photo

So now we can detect when the device is moving, we want our security camera to take a photo. How are we going to do this? Well, one feature of WebRTC is the ability to capture video with a device's video camera. At present, this is supported in Firefox and Chrome on the desktop, and the Blackberry 10 Browser (which also supports devicemotion events, so your Blackberry 10 phone or Playbook can serve as a security camera if you need it!), as well as Chrome for Android (though you need to enable it with chrome://flags). WebRTC is a very powerful API, but we're only going to need a small part of it.

We'll use the getUserMedia method of the navigator object. This takes an options object, as well as a success and a failure callback function as its arguments.

var options = {video: true};
navigator.getMedia(options, gotVideoStream, getStreamFailed);

Our options variable is a simple object, here we just set its property video to true (if we wanted audio we'd also set an audio property to true).

We've also passed it two callback functions, gotVideoStream, which will be called once a video stream is available, and getStreamFailed, which is called if we don't get a video stream (for example, if the user refuses the browser's request to use the video camera). getUserMedia uses callbacks, rather than returning a value, because it takes time for the user to choose whether to allow video to be enabled, and as JavaScript is single threaded, this would block our UI while the user waited.

Next, let's use video stream.

function gotVideoStream(stream) {
  var videoElement = document.querySelector("video");
  videoElement.src = window.URL.createObjectURL(stream);
}

OK, there's a bit going on here, so let's take it one step at a time. Navigator calls our callback function, passing an argument stream. This is a MediaStream object. We then use the createObjectURL method of the window's URL object to get a URL for the stream (this way we can then make this URL the value of the src attribute of a video element, then this video element will show the output of our camera in real time!).

So, we've now got a working video camera, that shows the video feed from our devices camera in a web page. No servers, no plugins! But we still don't quite have our security camera. What we need to do is take a snapshot from the video stream, when we detect movement. So, let's first take the snapshot

Taking a snapshot from the video element

Here we'll take a snapshot of the video element at a given time. Note this works regardless of what's playing in the video element (so you can do a screen grab of anything playing in an HTML5 video element like this). Ready?

function takeSnapshot(){
	var canvas = document.querySelector("canvas");
  var context = canvas.getContext('2d');
  var video = document.querySelector("video");
  context.drawImage(video, 0, 0);
}

Here's what we're doing

  • we get a canvas element from the page
  • we get its 2D drawing context
  • we get the video element from the page
  • we use the drawImage method of the canvas to draw the video into the canvas starting at (0, 0) (the top left of the canvas).

Yes, it really is that easy. Just as you can use canvas.drawImage with an img element, we can use it with a video element.

Now we've got all the pieces, let's put them together to create our security camera.

Remember this part of our motion detection functions?

if (inMotion) {
  //do something because it is in motion
}

This is where we call takeSnapshot, and then the current frame in the video element will be captured to a canvas element. You could also save this in localStorage, or send it via email to someone, or otherwise do something with the image. I'll leave those parts to you.

And that's really all there is to it.

I've also got a fully working version available on github. It's a little more complicated to read through than the code here, but it's copiously commented, and the basic working code is the same. Or you can see it in action here (just make sure you use Chrome with a device that supports orientation events, and has a webcam).

Notes for those following along

Note though, to make it work from your local drive, you'll need to run it through a webserver (Chrome won't enable the camera from file:// although Firefox will). You'll also need a device that supports either device orientation or device motion events, which to my knowledge currently means only a MacBook Pro (not MacBook Air).

Links for further reading

Som more reading on the various features we used to build our security camera.

" ["post_title"]=> string(84) "Build a motion activated security camera, with WebRTC, canvas and Device Orientation" ["post_excerpt"]=> string(0) "" ["post_status"]=> string(7) "publish" ["comment_status"]=> string(4) "open" ["ping_status"]=> string(4) "open" ["post_password"]=> string(0) "" ["post_name"]=> string(82) "build-a-motion-activated-security-camera-with-webrtc-canvas-and-device-orientation" ["to_ping"]=> string(0) "" ["pinged"]=> string(0) "" ["post_modified"]=> string(19) "2013-06-07 11:43:40" ["post_modified_gmt"]=> string(19) "2013-06-07 01:43:40" ["post_content_filtered"]=> string(0) "" ["post_parent"]=> int(0) ["guid"]=> string(36) "http://www.webdirections.org/?p=4693" ["menu_order"]=> int(0) ["post_type"]=> string(4) "post" ["post_mime_type"]=> string(0) "" ["comment_count"]=> string(3) "104" ["filter"]=> string(3) "raw" ["post_category"]=> string(1) "0" } [12]=> object(WP_Post)#259 (25) { ["ID"]=> int(4708) ["post_author"]=> string(1) "2" ["post_date"]=> string(19) "2013-06-07 11:28:24" ["post_date_gmt"]=> string(19) "2013-06-07 01:28:24" ["post_content"]=> string(675) "

The DOM will finally have real encapsulation with the introduction of the Shadow DOM, a subset of the Web Components spec that will revolutionise web development as we know it. In this session we’ll take a short, sharp tour on the how and why of what the Shadow DOM has to offer.

Like what you see? Want a piece of the action next time around? Then get along to Web Directions South in Sydney October 24 and 25 2013.

" ["post_title"]=> string(61) "Ghost in the Shadow DOM - Video presentation from Ryan Seddon" ["post_excerpt"]=> string(0) "" ["post_status"]=> string(7) "publish" ["comment_status"]=> string(4) "open" ["ping_status"]=> string(4) "open" ["post_password"]=> string(0) "" ["post_name"]=> string(59) "ghost-in-the-shadow-dom-video-presentation-from-ryan-seddon" ["to_ping"]=> string(0) "" ["pinged"]=> string(0) "" ["post_modified"]=> string(19) "2013-06-07 11:28:24" ["post_modified_gmt"]=> string(19) "2013-06-07 01:28:24" ["post_content_filtered"]=> string(0) "" ["post_parent"]=> int(0) ["guid"]=> string(36) "http://www.webdirections.org/?p=4708" ["menu_order"]=> int(0) ["post_type"]=> string(4) "post" ["post_mime_type"]=> string(0) "" ["comment_count"]=> string(1) "0" ["filter"]=> string(3) "raw" ["post_category"]=> string(1) "0" } [13]=> object(WP_Post)#257 (25) { ["ID"]=> int(4395) ["post_author"]=> string(1) "2" ["post_date"]=> string(19) "2012-08-10 10:21:14" ["post_date_gmt"]=> string(19) "2012-08-10 00:21:14" ["post_content"]=> string(3047) "

Andrew Fisher gets all touchy feely with the mobile web. See below for full session description and more resources.

Got a taste for it? Be there for the dev track at Web Directions South 2012.

This presentation was recorded at Web Directions Code in Melbourne on May 23 2012.

Session description

As the majority of web users shift to touch devices, the expectation is becoming that everything becomes touchable — including the mobile web. This session will provide a practical and pragmatic view of where touch is at from a web standards perspective and how you can start weaving touch interactions into your mobile web applications.

Resources from this presentation

About Andrew Fisher

Andrew Fisher is deeply passionate about technology and is constantly tinkering with and breaking something — whether it’s a new application for mobile computing, building a robot, deploying a cloud or just playing around with web tech. Sometimes he does some real work too and has been involved in developing digital solutions for businesses since the dawn of the web in Australia and Europe for brands like Nintendo, peoplesound, Sony, Mitsubishi, Sportsgirl and the Melbourne Cup.

Andrew is the CTO for JBA Digital, a data agency in Melbourne Australia, where he focuses on creating meaning out of large, changing data sets for clients. Andrew is also the founder of Rocket Melbourne, a startup technology lab exploring physical computing and the Web of Things.

" ["post_title"]=> string(60) "Getting all touchy feely with the mobile web - Andrew Fisher" ["post_excerpt"]=> string(497) "

Photo of Andrew FisherAs the majority of web users shift to touch devices, the expectation is becoming that everything becomes touchable — including the mobile web. This session will provide a practical and pragmatic view of where touch is at from a web standards perspective and how you can start weaving touch interactions into your mobile web applications.

" ["post_status"]=> string(7) "publish" ["comment_status"]=> string(4) "open" ["ping_status"]=> string(4) "open" ["post_password"]=> string(0) "" ["post_name"]=> string(58) "getting-all-touchy-feely-with-the-mobile-web-andrew-fisher" ["to_ping"]=> string(0) "" ["pinged"]=> string(0) "" ["post_modified"]=> string(19) "2012-08-10 10:21:14" ["post_modified_gmt"]=> string(19) "2012-08-10 00:21:14" ["post_content_filtered"]=> string(0) "" ["post_parent"]=> int(0) ["guid"]=> string(36) "http://www.webdirections.org/?p=4395" ["menu_order"]=> int(0) ["post_type"]=> string(4) "post" ["post_mime_type"]=> string(0) "" ["comment_count"]=> string(1) "0" ["filter"]=> string(3) "raw" ["post_category"]=> string(1) "0" } [14]=> object(WP_Post)#256 (25) { ["ID"]=> int(4376) ["post_author"]=> string(1) "2" ["post_date"]=> string(19) "2012-07-12 16:11:36" ["post_date_gmt"]=> string(19) "2012-07-12 06:11:36" ["post_content"]=> string(2267) "

Rob Hawkes uses HTML5 technologies for game development. See below for full session description and more resources.

Got a taste for it? Be there for the dev track at Web Directions South 2012.

This presentation was recorded at Web Directions Code in Melbourne on May 24 2012.

Session description

With Angry Birds, Cut the Rope and other block­buster games now working in modern web browsers, it’s fair to say native, browser based gaming has arrived for real. But how do they do it? In this session, Mozilla Technical Evangelist Rob Hawkes looks at the features now in your browsers to help develop games (and other interactive web based experiences) including the Canvas and WebGL, HTML5 Audio API, Mouselock and the Joy­stick API.

Resources from this presentation

About Rob Hawkes

Rob thrives on solving problems through code. He has an addiction to visual programming and can’t get enough of HTML5 and JavaScript. He’s the author of Foundation HTML5 Canvas and is a Technical Evangelist at Mozilla. He leads the gaming side of Mozilla’s work within the developer community.

" ["post_title"]=> string(52) "HTML5 technologies and game development - Rob Hawkes" ["post_excerpt"]=> string(596) "

Photo of Rob HawkesWith Angry Birds, Cut the Rope and other block­buster games now working in modern web browsers, it’s fair to say native, browser based gaming has arrived for real. But how do they do it? In this session, Mozilla Technical Evangelist Rob Hawkes looks at the features now in your browsers to help develop games (and other interactive web based experiences) including the Canvas and WebGL, HTML5 Audio API, Mouselock and the Joy­stick API.

" ["post_status"]=> string(7) "publish" ["comment_status"]=> string(4) "open" ["ping_status"]=> string(4) "open" ["post_password"]=> string(0) "" ["post_name"]=> string(39) "html5-technologies-and-game-development" ["to_ping"]=> string(0) "" ["pinged"]=> string(0) "" ["post_modified"]=> string(19) "2012-08-10 10:15:21" ["post_modified_gmt"]=> string(19) "2012-08-10 00:15:21" ["post_content_filtered"]=> string(0) "" ["post_parent"]=> int(0) ["guid"]=> string(36) "http://www.webdirections.org/?p=4376" ["menu_order"]=> int(0) ["post_type"]=> string(4) "post" ["post_mime_type"]=> string(0) "" ["comment_count"]=> string(1) "0" ["filter"]=> string(3) "raw" ["post_category"]=> string(1) "0" } } ["post"]=> object(WP_Post)#229 (25) { ["ID"]=> int(5471) ["post_author"]=> string(1) "3" ["post_date"]=> string(19) "2013-12-03 16:25:04" ["post_date_gmt"]=> string(19) "2013-12-03 06:25:04" ["post_content"]=> string(704) "

In a fast and furious fifteen minutes, Mark Dalgleish demystifies Web Components by highlighting how, despite its complex appearance, it's actually made up of a suite of technologies providing features we're already familiar with. Once you understand what web components bring to the table, you'll wonder how we ever lived without them. Make sure you also check out the accompanying blog post for full details.

[iframe width="500" height="281" src="//www.youtube.com/embed/s1PTPZwzQA4?list=UURx1y52pfeMwbuer9Vh2u-A" frameborder="0" Mozallowfullscreen Webkitallowfullscreen allowfullscreen]" ["post_title"]=> string(55) "Web Components - video presentation from Mark Dalgleish" ["post_excerpt"]=> string(0) "" ["post_status"]=> string(7) "publish" ["comment_status"]=> string(4) "open" ["ping_status"]=> string(4) "open" ["post_password"]=> string(0) "" ["post_name"]=> string(53) "web-components-video-presentation-from-mark-dalgleish" ["to_ping"]=> string(0) "" ["pinged"]=> string(0) "" ["post_modified"]=> string(19) "2013-12-05 10:53:33" ["post_modified_gmt"]=> string(19) "2013-12-05 00:53:33" ["post_content_filtered"]=> string(0) "" ["post_parent"]=> int(0) ["guid"]=> string(36) "http://www.webdirections.org/?p=5471" ["menu_order"]=> int(0) ["post_type"]=> string(4) "post" ["post_mime_type"]=> string(0) "" ["comment_count"]=> string(1) "0" ["filter"]=> string(3) "raw" ["post_category"]=> string(1) "0" } ["queried_object"]=> object(stdClass)#382 (10) { ["term_id"]=> string(3) "126" ["name"]=> string(5) "html5" ["slug"]=> string(5) "html5" ["term_group"]=> string(1) "0" ["term_order"]=> string(1) "0" ["term_taxonomy_id"]=> string(3) "127" ["taxonomy"]=> string(8) "post_tag" ["description"]=> string(0) "" ["parent"]=> string(1) "0" ["count"]=> string(2) "36" } ["queried_object_id"]=> int(126) }

Presentations about html5

Podcasts, slides, videos and more

Web Components — video presentation from Mark Dalgleish

In a fast and furious fifteen minutes, Mark Dalgleish demystifies Web Components by highlighting how, despite its complex appearance, it's actually made up of a suite of technologies providing features we're already familiar with. Once you understand what web components bring to the table, you'll wonder how we ever lived without them. Make sure you also check out the accompanying blog post for full details.

See the slides and hear the podcast »

Validating forms with the HTML5 pattern attribute — video presentation by Chris Lienert

In the past, validating forms in the client has typically required doing some heavy lifting with JavaScript. But you may not know HTML5 changes all that. Browsers now check that the content of an input match its type (and we've got new types like email, url and number to make that even more useful). But, what you might not know about is the pattern attribute, which lets us use regular expressions directly in HTML to specify what format the user's input should have.

In this session, Chris Lienert looks at some of the common regex patterns you can use to validate user input, coupled with some of the many tricks he's learned to help users complete those forms we all love to hate.

See the slides and hear the podcast »

Making Web Apps as Smooth as Native — video presentation by Andrew Betts

Right now creating high quality user experiences in HTML5 is very hard, and to get to where we are today we need a huge bundle of hacks and extreme techniques, many of which Andrew Betts covers in the session.

See the slides and hear the podcast »

Appcache, not so much a douchebag as a complete pain in the #$%^

A little while back, Jake Archibald wrote infamously (and anthropomorphically) that the HTML5 ApplicationCache is a “douchebag“[1]. Mindful that this is a word freighted with troubling significance, it is the term he used, so I’ll go with it.

The Urban Dictionary says the word douchebag

generally refers to a male … Read more »

WebRTC now in Chrome Beta for Android

Chrome Android Image

Following Blackberry 10’s support for WebRTC, Chrome beta or Android now supports webRTC, as do Firefox, Opera and Chrome for desktop (and Firefox for Android though not as yet Firefox OS it would seem).

A very significant milestone for what many consider a game … Read more »

More HTML5 syntax and parser quirks you may not have known

Last week we looked at one of HTML5’s syntax quirks, the fact that you don’t need to quote attribute values (unless the values contain a space or as is less well known one of a number of other characters). This time, some more about some of the subtle side … Read more »

Five reasons why you should quote attribute values in HTML5

With HTML5, you don’t have to quote attribute values. Until you do.

One of the benefits often touted for HTML5 over XHTML is what I once heard Paul Irish describe as its “loosey goosey” approach to syntax. No longer the strict taskmaster that XHTML was, we can now do all … Read more »

The iOS 7 homescreen parallax effect in the browser

A couple of weeks ago we started a series on how you might implement some of the more notable design effects in iOS 7 using purely web technologies. In the meantime, it’s been noted elsewhere that this may be difficult and perhaps impossible to do. I’m here today … Read more »

Wii Games with HTML5

Nintendo Web Framework Logo

For most of the history of what might loosely be termed computer games, dedicated consoles (and handheld gaming devices) ruled the roost. And none loomed larger on the landscape than Nintendo, with combined sales of hundreds of millions of units.

The dominance of this handful … Read more »

Towards an extensible web

Remember the X in XML, and XHTML? It of course stands for extensible, the idea that these languages allow for their users to build upon them, rather than waiting for some standards organisation to add new features.

With HTML5, extensibility of the markup language pretty much went out the window, despite … Read more »

HTML, CSS and the Clientside App — Video Presentation from Garann Means

As much as they affect JavaScript, state, event handling, and default browser behaviour also impact HTML and CSS in the choices we make, optimizations we can take advantage of, and the architecture of our applications as a whole.

Like what you see? Want a piece of the action next time around? Then get along to Web Directions South in Sydney October 24 and 25 2013.

See the slides and hear the podcast »

Build a motion activated security camera, with WebRTC, canvas and Device Orientation

As a web developer, you’ve probably seen emerging HTML5 technologies and APIs like DeviceOrientation and WebRTC (Web Real Time Communications), and thought “wow they look cool, but they are only for hard core gaming, video conferencing, and other such stuff, not for my every day development”. I’m firmly … Read more »

Ghost in the Shadow DOM — Video presentation from Ryan Seddon

The DOM will finally have real encapsulation with the introduction of the Shadow DOM, a subset of the Web Components spec that will revolutionise web development as we know it. In this session we’ll take a short, sharp tour on the how and why of what the Shadow DOM has to offer.

Like what you see? Want a piece of the action next time around? Then get along to Web Directions South in Sydney October 24 and 25 2013.

See the slides and hear the podcast »

Getting all touchy feely with the mobile web — Andrew Fisher

Photo of Andrew FisherAs the majority of web users shift to touch devices, the expectation is becoming that everything becomes touchable — including the mobile web. This session will provide a practical and pragmatic view of where touch is at from a web standards perspective and how you can start weaving touch interactions into your mobile web applications.

See the slides and hear the podcast »

HTML5 technologies and game development — Rob Hawkes

Photo of Rob HawkesWith Angry Birds, Cut the Rope and other block­buster games now working in modern web browsers, it’s fair to say native, browser based gaming has arrived for real. But how do they do it? In this session, Mozilla Technical Evangelist Rob Hawkes looks at the features now in your browsers to help develop games (and other interactive web based experiences) including the Canvas and WebGL, HTML5 Audio API, Mouselock and the Joy­stick API.

See the slides and hear the podcast »