Seeing what other people do in an audience at a conference can be interesting. When waiting for the next talk in the incredibly claustrophobic seats at FOSDEM last week I saw something that got my attention: the Desktop of an operating system being debugged using a web inspector:
Turns out, the guys doing that are from Jolicloud – a company that strives to offer a OS alternative for old and low-spec computers by only providing basic OS tasks and leaving the day-to-day work tasks to web applications hosted in the cloud. Sounds familiar? Google does the same with their Chrome OS and the Cr48. The main difference is that Jolicloud is based in Europe and a dedicated, affordable Netbook is available even for us across the pond.
Jolicloud is an interesting approach to fix the problem of outdated hardware and any Desktop system that runs on HTML, CSS and JavaScript gets my attention. Hence I took the opportunity to interview the guys on the spot and get some answers:
Mike Cardwell has found an interesting way to detect if you are logged into social web sites. The easiest trick lies with GMail. Mike created a photo and uploaded it to Google. If you add this image to an HTML document and add event handlers for the success and failure case you can check if the visitor is logged in or not – as the photo gets delivered when you are and GMail delivers a 404 document when you are not:
This works in all browsers and can be used to for example send mailto: links to GMail directly. Notice that this just checks that you are logged in, it doesn’t mean you get access to content.
For Facebook and Twitter, this doesn’t quite work. Instead, Mike tries to read content with the APIs and relies on errors to be thrown on 404 responses:
This fails to work in Internet Explorer and Opera, but still works nicely for the other browsers. In Firefox you can work around this using the Request Policy add-on.
It’d be interesting to see what other social web sites can be detected with some simple onload and onerror handlers. Know any others?
Editor’s note: This article is posted by Chris Heilmann but authored by Jeff Walden – credit where credit is due.
Developers in the Mozilla community have made major improvements to the JavaScript engine in Firefox 4. We have devoted much effort to improving performance, but we’ve also worked on new features. We have particularly focused on ECMAScript 5, the latest update to the standard underlying JavaScript.
Strict mode is arguably the most interesting new feature in ECMAScript 5. It’s a way to opt in to a restricted variant of JavaScript. Strict mode isn’t just a subset: it intentionally has different semantics from normal code. Browsers not supporting strict mode will run strict mode code with different behavior from browsers that do, so don’t rely on strict mode without feature-testing for support for the relevant aspects of strict mode.
Strict mode code and non-strict mode code can coexist, so scripts can opt into strict mode incrementally. Strict mode blazes a path to future ECMAScript editions where new code with a particular <script type="..."> will likely automatically be executed in strict mode.
What does strict mode do? First, it eliminates some JavaScript pitfalls that didn’t cause errors by changing them to produce errors. Second, it fixes mistakes that make it difficult for JavaScript engines to perform optimizations: strict mode code can sometimes be made to run faster than identical code that’s not strict mode. Firefox 4 generally hasn’t optimized strict mode yet, but subsequent versions will. Third, it prohibits some syntax likely to be defined in future versions of ECMAScript.
Invoking strict mode
Strict mode applies to entire scripts or to individual functions. It doesn’t apply to block statements enclosed in {} braces; attempting to apply it to such contexts does nothing. eval code, event handler attributes, strings passed to setTimeout, and the like are entire scripts, and invoking strict mode in them works as expected.
Strict mode for scripts
To invoke strict mode for an entire script, put the exact statement "use strict"; (or 'use strict';) before any other statements.
// Whole-script strict mode syntax"use strict";var v ="Hi! I'm a strict mode script!";
This syntax has a trap that has already bittena major site: it isn’t possible to blindly concatenate non-conflicting scripts. Consider concatenating a strict mode script with a non-strict mode script: the entire concatenation looks strict! The inverse is also true: non-strict plus strict looks non-strict. Concatenation of strict mode scripts with each other is fine, and concatenation of non-strict mode scripts is fine. Only crossing the streams by concatenating strict and non-strict scripts is problematic.
Strict mode for functions
Likewise, to invoke strict mode for a function, put the exact statement "use strict"; (or 'use strict';) in the function’s body before any other statements.
function strict(){// Function-level strict mode syntax'use strict';function nested(){return"And so am I!";}return"Hi! I'm a strict mode function! "+ nested();}function notStrict(){return"I'm not strict.";}
Changes in strict mode
Strict mode changes both syntax and runtime behavior. Changes generally fall into these categories:
Converting mistakes into errors (as syntax errors or at runtime)
Simplifying how the particular variable for a given use of a name is computed
Simplifying eval and arguments
Making it easier to write “secure” JavaScript
Anticipating future ECMAScript evolution
Converting mistakes into errors
Strict mode changes some previously-accepted mistakes into errors. JavaScript was designed to be easy for novice developers, and sometimes it gives operations which should be errors non-error semantics. Sometimes this fixes the immediate problem, but sometimes this creates worse problems in the future. Strict mode treats these mistakes as errors so that they’re discovered and promptly fixed.
First, strict mode makes it impossible to accidentally create global variables. In normal JavaScript, mistyping a variable in an assignment creates a new property on the global object and continues to “work” (although future failure is possible: likely, in modern JavaScript). Assignments which would accidentally create global variables instead throw errors in strict mode:
"use strict";
mistypedVaraible =17;// throws a ReferenceError
Second, strict mode makes assignments which would otherwise silently fail throw an exception. For example, NaN is a non-writable global variable. In normal code assigning to NaN does nothing; the developer receives no failure feedback. In strict mode assigning to NaN throws an exception. Any assignment that silently fails in normal code will throw errors in strict mode:
"use strict";NaN=42;// throws a TypeErrorvar obj ={get x(){return17;}};
obj.x=5;// throws a TypeErrorvar fixed ={};Object.preventExtensions(fixed);
fixed.newProp="ohai";// throws a TypeError
Third, if you attempt to delete undeletable properties, strict mode throws errors (where before the attempt would simply have no effect):
"use strict";deleteObject.prototype;// throws a TypeError
Fourth, strict mode requires that all properties named in an object literal be unique. Normal code may duplicate property names, with the last one determining the property’s value. But since only the last one does anything, the duplication is simply a vector for bugs, if the code is modified to change the property value other than by changing the last instance. Duplicate property names are a syntax error in strict mode:
"use strict";var o ={ p:1, p:2};// !!! syntax error
Fifth, strict mode requires that function argument names be unique. In normal code the last duplicated argument hides previous identically-named arguments. Those previous arguments remain available through arguments[i], so they’re not completely inaccessible. Still, this hiding makes little sense and is probably undesirable (it might hide a typo, for example), so in strict mode duplicate argument names are a syntax error:
function sum(a, a, c)// !!! syntax error{"use strict";return a + b + c;// wrong if this code ran}
Sixth, strict mode forbids octal syntax. Octal syntax isn’t part of ECMAScript, but it’s supported in all browsers by prefixing the octal number with a zero: 0644 === 420 and "\\045" === "%". Novice developers sometimes believe a leading zero prefix has no semantic meaning, so they use it as an alignment device — but this changes the number’s meaning! Octal syntax is rarely useful and can be mistakenly used, so strict mode makes octal a syntax error:
"use strict";var sum = 015 +// !!! syntax error197+142;
Simplifying variable uses
Strict mode simplifies how variable uses map to particular variable definitions in the code. Many compiler optimizations rely on the ability to say that this variable is stored in this location: this is critical to fully optimizing JavaScript code. JavaScript sometimes makes this basic mapping of name to variable definition in the code impossible to perform except at runtime. Strict mode removes most cases where this happens, so the compiler can better optimize strict mode code.
First, strict mode prohibits with. The problem with with is that any name in it might map either to a property of the object passed to it, or to a variable in surrounding code, at runtime: it’s impossible to know which beforehand. Strict mode makes with a syntax error, so there’s no chance for a name in a with to refer to an unknown location at runtime:
"use strict";var x =17;
with (obj)// !!! syntax error{// If this weren't strict mode, would this be var x, or// would it instead be obj.x? It's impossible in general// to say without running the code, so the name can't be// optimized.
x;}
The simple alternative of assigning the object to a variable, then accessing the corresponding property on that variable, stands ready to replace with.
Second, eval of strict mode code does not introduce new variables into the surrounding code. In normal code eval("var x;") introduces a variable x into the surrounding function or the global scope. This means that, in general, in a function containing a call to eval, every name not referring to an argument or local variable must be mapped to a particular definition at runtime (because that eval might have introduced a new variable that would hide the outer variable). In strict mode eval creates variables only for the code being evaluated, so eval can’t affect whether a name refers to an outer variable or some local variable:
var x =17;var evalX = eval("'use strict'; var x = 42; x");
assert(x ===17);
assert(evalX ===42);
Relatedly, if the function eval is invoked by an expression of the form eval(...) in strict mode code, the code will be evaluated as strict mode code. The code may explicitly invoke strict mode, but it’s unnecessary to do so.
function strict1(str){"use strict";return eval(str);// str will be treated as strict mode code}function strict2(f, str){"use strict";return f(str);// not eval(...): str is strict iff it invokes strict mode}function nonstrict(str){return eval(str);// str is strict iff it invokes strict mode}
strict1("'Strict mode code!'");
strict1("'use strict'; 'Strict mode code!'");
strict2(eval,"'Non-strict code.'");
strict2(eval,"'use strict'; 'Strict mode code!'");
nonstrict("'Non-strict code.'");
nonstrict("'use strict'; 'Strict mode code!'");
Third, strict mode forbids deleting plain names. Thus names in strict mode eval code behave identically to names in strict mode code not being evaluated as the result of eval. Using delete name in strict mode is a syntax error:
Strict mode makes arguments and eval less bizarrely magical. Both involve a considerable amount of magical behavior in normal code: eval to add or remove bindings and to change binding values, and arguments by its indexed properties aliasing named arguments. Strict mode makes great strides toward treating eval and arguments as keywords, although full fixes will not come until a future edition of ECMAScript.
First, the names eval and arguments can’t be bound or assigned in language syntax. All these attempts to do so are syntax errors:
"use strict";
eval =17;
arguments++;++eval;var obj ={set p(arguments){}};var eval;try{}catch(arguments){}function x(eval){}function arguments(){}var y =function eval(){};var f =newFunction("arguments","'use strict'; return 17;");
Second, strict mode code doesn’t alias properties of arguments objects created within it. In normal code within a function whose first argument is arg, setting arg also sets arguments[0], and vice versa (unless no arguments were provided or arguments[0] is deleted). For strict mode functions, arguments objects store the original arguments when the function was invoked. The value of arguments[i] does not track the value of the corresponding named argument, nor does a named argument track the value in the corresponding arguments[i].
function f(a){"use strict";
a =42;return[a, arguments[0]];}var pair = f(17);
assert(pair[0]===42);
assert(pair[1]===17);
Third, arguments.callee is no longer supported. In normal code arguments.callee refers to the enclosing function. This use case is weak: simply name the enclosing function! Moreover, arguments.callee substantially hinders optimizations like inlining functions, because it must be made possible to provide a reference to the un-inlined function if arguments.callee is accessed. For strict mode functions, arguments.callee is a non-deletable property which throws an error when set or retrieved:
"use strict";var f =function(){return arguments.callee;};
f();// throws a TypeError
“Securing” JavaScript
Strict mode makes it easier to write “secure” JavaScript. Some websites now provide ways for users to write JavaScript which will be run by the website on behalf of other users. JavaScript in browsers can access the user’s private information, so such JavaScript must be partially transformed before it is run, to censor access to forbidden functionality. JavaScript’s flexibility makes it effectively impossible to do this without many runtime checks. Certain language functions are so pervasive that performing runtime checks has considerable performance cost. A few strict mode tweaks, plus requiring that user-submitted JavaScript be strict mode code and that it be invoked in a certain manner, substantially reduce the need for those runtime checks.
First, the value passed as this to a function in strict mode isn’t boxed into an object. For a normal function, this is always an object: the provided object if called with an object-valued this; the value, boxed, if called with a Boolean, string, or number this; or the global object if called with an undefined or nullthis. (Use call, apply, or bind to specify a particular this.) Automatic boxing is a performance cost, but exposing the global object in browsers is a security hazard, because the global object provides access to functionality “secure” JavaScript environments must invariably. Thus for a strict mode function, the specified this is used unchanged:
(Tangentially, built-in methods also now won’t box this if it is null or undefined. [This change is independent of strict mode but is motivated by the same concern about exposing the global object.] Historically, passing null or undefined to a built-in method like Array.prototype.sort() would act as if the global object had been specified. Now passing either value as this to most built-in methods throws a TypeError. Booleans, numbers, and strings are still boxed by these methods: it’s only when these methods would otherwise act on the global object that they’ve been changed.)
Second, in strict mode it’s no longer possible to “walk” the JavaScript stack via commonly-implemented extensions to ECMAScript. In normal code with these extensions, when a function fun is in the middle of being called, fun.caller is the function that most recently called fun, and fun.arguments is the arguments for that invocation of fun. Both extensions are problematic for “secure” JavaScript, because they allow “secured” code to access “privileged” functions and their (potentially unsecured) arguments. If fun is in strict mode, both fun.caller and fun.arguments are non-deletable properties which throw an error when set or retrieved:
function restricted(){"use strict";
restricted.caller;// throws a TypeError
restricted.arguments;// throws a TypeError}function privilegedInvoker(){return restricted();}
privilegedInvoker();
Third, arguments for strict mode functions no longer provide access to the corresponding function call’s variables. In some old ECMAScript implementations arguments.caller was an object whose properties aliased variables in that function. This is a security hazard because it breaks the ability to hide privileged values via function abstraction; it also precludes most optimizations. For these reasons no recent browsers implement it. Yet because of its historical functionality, arguments.caller for a strict mode function is also a non-deletable property which throws an error when set or retrieved:
"use strict";function fun(a, b){"use strict";var v =12;return arguments.caller;// throws a TypeError}
fun(1,2);// doesn't expose v (or a or b)
Paving the way for future ECMAScript versions
Future ECMAScript versions will likely introduce new syntax, and strict mode in ECMAScript 5 applies some restrictions to ease the transition. It will be easier to make some changes if the foundations of those changes are prohibited in strict mode.
First, in strict mode a short list of identifiers become reserved keywords. These words are implements, interface, let, package, private, protected, public, static, and yield. In strict mode, then, you can’t name or use variables or arguments with these names. A Mozilla-specific caveat: if your code is JavaScript 1.7 or greater (you’re chrome code, or you’ve used the right <script type="">) and is strict mode code, let and yield have the functionality they’ve had since those keywords were first introduced. But strict mode code on the web, loaded with <script src=""> or <script>...</script>, won’t be able to use let/yield as identifiers.
"use strict";if(true){function f(){}// !!! syntax error
f();}for(var i =0; i <5; i++){function f2(){}// !!! syntax error
f2();}function baz()// kosher{function eit(){}// also kosher}
This prohibition isn’t strict mode proper, because such function statements are an extension. But it is the recommendation of the ECMAScript committee, and browsers will implement it.
Strict mode in browsers
Firefox 4 is the first browser to fully implement strict mode. The Nitro engine found in many WebKit browsers isn’t far behind with nearly-complete strict mode support. Chrome has also started to implement strict mode. Internet Explorer and Opera haven’t started to implement strict mode; feel free to send those browser makers feedback requesting strict mode support.
Browsers don’t reliably implement strict mode, so don’t blindly depend on it. Strict mode changes semantics. Relying on those changes will cause mistakes and errors in browsers which don’t implement strict mode. Exercise caution in using strict mode, and back up reliance on strict mode with feature tests that check whether relevant features of strict mode are implemented.
To test out strict mode, download a Firefox nightly and start playing. Also consider its restrictions when writing new code and when updating existing code. (To be absolutely safe, however, it’s probably best to wait to use it in production until it’s shipped in browsers.)
There are dozens of video players that allow you to do all the normal things with videos: play, pause, jump to a certain time and so on. More advanced ones also allow you to fast forward and reverse the video and support subtitles.
One thing I haven’t found yet though is zooming and rotation of a video. Granted, an edge use case, but sometimes it is cool to be able to zoom into a detail like a blooper (boom mic in the background) or an easter egg (check for the term “A 113″ in every Pixar movie – an homage to the classroom most of the original Pixar cast learned their trade in).
Rotation might come in handy when you recorded your video in portrait instead of landscape on your camera and you don’t want to re-encode it before you put it on the web.
The HTML5 video tag allows you to style the video with CSS and CSS3 transforms allow both for scaling and for rotation. So let’s put those together.
Embedding a video is as simple as this (see this in action on the demo page):
<video controls><sourcesrc="http://www.archive.org/download/AnimatedMechanicalArtPiecesAtMit/P1120973_512kb.mp4"type="video/mp4"><sourcesrc="http://www.archive.org/download/AnimatedMechanicalArtPiecesAtMit/P1120973.ogv"type="video/ogg"><p>Your browser doesn't support the HTML5 video tag it seems.
You can see this video as part of a collection <ahref="http://www.archive.org/download/AnimatedMechanicalArtPiecesAtMit/">at archive.org</a>.</p></video>
Now, to scale this video you can use CSS3 transform:scale:
Now, this doesn’t make much sense though as it changes the dimension of the video (in the demo page I needed to change the margin for each video accordingly). To really provide a “zoom” functionality, we’d need to keep the original size and cut off the parts we don’t need. We could do this using a CANVAS element, but why go that far when a simple DIV does the job for us?
All we need to do to keep the space is nest our videos in a DIV with the class stage:
<divclass="stage"><video controls><sourcesrc="http://www.archive.org/download/AnimatedMechanicalArtPiecesAtMit/P1120973_512kb.mp4"type="video/mp4"><sourcesrc="http://www.archive.org/download/AnimatedMechanicalArtPiecesAtMit/P1120973.ogv"type="video/ogg"><p>Your browser doesn't support the HTML5 video tag it seems.
You can see this video as part of a collection <ahref="http://www.archive.org/download/AnimatedMechanicalArtPiecesAtMit/">at archive.org</a>.</p></video></div>
The CSS to make the cropping work is the following:
In order to provide a zoom and rotate functionality, we need to use JavaScript and buttons for the end user. The first hurdle here is – as you probably already realised from the CSS – browser differences in the syntax. Therefore we need to detect which of the transformations the current browser supports. The safest way is to ask the browser:
Once this runs we can set a transformation with the following JavaScript syntax:
var zoom =1.5;var rotate =20;
v.style[prop]='rotate('+rotate+'deg) scale('+zoom+')';
Of course it doesn’t make much sense to rotate the controls with the video. Therefore you need to provide your own. You can use any of the aforementioned players for that or roll your own. To demonstrate, I just built one with a single button allowing you to play and pause the video:
HTML5 needs spokespeople to work. There are a lot of people out there who took on this role, and here at Mozilla we thought it is a good idea to introduce some of them to you with a series of interviews and short videos. The format is simple – we send the experts 10 questions to answer and then do a quick video interview to let them introduce themselves and ask for more detail on some of their answers.
Remy is one of those ubiquitous people of HTML5. Whenever something needed fixing, there is probably something on GitHub that Remy wrote that helps you. He is also very English and doesn’t mince his words much.
1) Reading “Introducing HTML5″ it seems to me that you were more of the API – focused person and Bruce the markup guy. Is that a fair assumption? What is your background and passion?
That’s spot on. Bruce asked me to join the project as the “JavaScript guy” – which is the slogan I wear under my clothes and frequently reveal in a superman ‘spinning around’ fashion (often at the surprise of clients).
My background has always been coding – even from a young age, my dad had me copying out listings from old spectrum magazines only to result in hours of typing and some random error that I could never debug.
As I got older I graduated to coding in C but those were the days the SDKs were 10Mb downloaded over a 14kb modem, and compile in to some really odd environment. Suffice to say I didn’t get very far.
Then along came JavaScript. A programming language that didn’t require any special development environment. I could write the code in Notepad on my dodgy Window 95 box, and every machine came with the runtime: the browser. Score!
From that point on the idea of instant gratification from the browser meant that I was converted – JavaScript was the way for me.
Since then I’ve worked on backend environments too (yep, I’m a Perl guy, sorry!), but always worked and played in the front end in some way or another. However, since started on my own in 2006, it’s allowed me to move focus almost entirely on the front end, and specialise in JavaScript. Basically, work-wise: I’m a pig in shit [Ed: for our non-native English readers, he means "happy")].
2) From a programmer’s point of view, what are the most exciting bits about the HTML5 standard? What would you say is something every aspiring developer should get their head around first?
For me, the most exciting aspects of HTML5 is the depth of the JavaScript APIs. It’s pretty tricky to explain to Joe Bloggs that actually this newly spec’ed version of HTML isn’t mostly HTML; it’s mostly JavaScript.
I couldn’t put my finger on one single part of the spec, only because it’s like saying which is your favourite part of CSS (the :target selector – okay, so I can, but that’s not the point!). What’s most exciting to me is that HTML5 is saying that the browser is the platform that we can deliver real applications – take this technology seriously.
If an aspiring developer wanted something quick and impressive, I’d say play around with the video API – by no means is this the best API, just an easy one.
If they really wanted to blow people away with something amazing using HTML5, I’d say learn JavaScript (I’m assuming they’re already happy with HTML and CSS). Get a book like JavaScript: The Good Parts and then get JavaScript Patterns and master the language. Maybe, just maybe, then go buy Introducing HTML5, it’s written by two /really/ good looking (naked) guys: http://flic.kr/p/8iyQTE and http://flic.kr/p/8iy6Z1[Ed: maybe NSFW, definitely disturbing].
3) In your book you wrote a nice step-by-step video player for HTML5 video. What do you think works well with the Video APIs and what are still problems that need solving?
The media API is dirt simple, so it means working with video and audio is a doddle. For me, most of it works really well (so long as you understand the loading process and the events).
Otherwise what’s really quite neat, is the fact I can capture the video frames and mess with them in a canvas element – there’s lots of fun that can be had there (see some of Paul Rouget’s demos for that!).
What sucks, and sucks hard, is the spec asks vendors, ie. browser makers, *not* to implement full screen mode. It uses security concerns as the reason (which I can understand), but Flash solved this long ago – so why not follow their lead on this particular problem? If native video won’t go full screen, it will never be a competitive alternative to Flash for video.
That all said, I do like that the folks behind WebKit went and ignored the spec, and implemented full screen. The specs are just guidelines, and personally, I think browsers should be adding this feature.
4) Let’s talk a bit about non-HTML5 standards, like Geolocation. I understand you did some work with that and found that some parts of the spec work well whilst others less so. Can you give us some insight?
On top of HTML5 specification there’s a bunch more specs that make the browser really, really exciting. If we focus on the browser being released today (IE9 included) there’s a massive amount that can be done that we couldn’t do 10 years ago.
There’s the “non-HTML5″ specs that actually were part of HTML5, but split out for good reason (so they can be better managed), like web storage, 2D canvas API and Web Sockets, but there’s also the /really/ “nothing-to-do-with-HTML5″ APIs (NTDWH5API!) like querySelector, XHR2 and the Device APIs. I’m super keen to try all of these out even if they’re not fully there in all the browsers.
Geolocation is a great example of cherry picking technology. Playing against the idea that the technology isn’t fully implemented. Something I find myself ranting on and on about when it comes to the question of whether a developer should use HTML5. Only 50% of Geolocation is implemented in the browsers supporting it, in that they don’t have altitude, heading or speed – all of which are part of the spec. Does that stop mainstream apps like Google Maps from using the API? (clue: no).
The guys writting the specs have done a pretty amazing job, and in particular there are few cases where the specs have been retrospectively written. XHR is one of these and now we’ve got a stable API being added in new browsers (i.e. IE6 sucks, yes, we all know that). Which leads us to drag and drop. The black sheep of the APIs. In theory a really powerful API that could make our applications rip, but the technical implementation is a shambles. PPK (Peter-Paul Koch) tore the spec a bit of a ‘new one’. It’s usable, but it’s confusing, and lacking.
Generally, I’ve found the “non-HTML5″ specs to be a bit of mixed bag. Some are well supported in new browsers, some not at all. SVG is an oldie and now really viable with the help of JavaScript libraries such as Raphaël.js or SVGWeb (a Flash based solution). All in all, there’s lots of options available in JavaScript API nowadays compared to back in the dark ages.
5) Let’s talk Canvas vs. SVG for a bit. Isn’t Canvas just having another pixel-based rectangle in the page much like Java Applets used to be? SVG, on the other hand is Vector based and thus would be a more natural tool to do something with open standards that we do in Flash now. When would you pick SVG instead of Canvas and vice versa?
Canvas, in a lot of ways is just like the Flash drawing APIs. It’s not accessible and a total black box. The thing is, in the West, there’s a lot of businesses, rightly or wrongly, that want their fancy animation thingy to work on iOS. Since Flash doesn’t work there, canvas is a superb solution.
However, you must, MUST, decide which technology to use. Don’t just use canvas because you saw a Mario Kart demo using it. Look at the pros and cons of each. SVG and the canvas API are not competitive technologies, they’re specially shaped hammers for specific jobs.
Brad Neuberg did a superb job of summarising the pros and cons of each, and I’m constantly referring people to it (here’s the video).
So it really boils down to:
Canvas: pixel manipulation, non-interactive and high animation
SVG: interactive, vector based
Choose wisely young padawan!
6) What about performance? Aren’t large Canvas solutions very slow, especially on mobile devices? Isn’t that a problem for gaming? What can be done to work around that?
Well…yes and no. I’m finishing a project that has a large canvas animation going on, and it’s not slow on mobile devices (not that it was designed for those). The reason it’s not slow is because of the way the canvas animates. It doesn’t need to be constantly updating at 60fps.
Performance depends on your application. Evaluate the environment, the technologies and make a good decision. I personally don’t think using a canvas for a really high performance game on a mobile is quite ready. I don’t think the devices have the ommph to get the job done – but there’s a hidden problem – the browser in the device isn’t quite up to it. Hardware acceleration is going to help, a lot, but today, right now, I don’t think we’ll see games like Angry Birds written in JavaScript.
That said… I’ve seriously considered how you could replicate a game like Canabalt using a mix of canvas, DIVs and CSS. I think it might be doable ::throws gauntlet::
I think our community could actually learn a lot from the Flash community. They’ve been through all of this already. Trying to make old versions of Flash from years back do things that were pushing the boundaries. People like Seb Lee-Delisle (@seb_ly / http://seb.ly) are doing an amazing job of teaching both the Flash and JavaScript community.
7) A feature that used to be HTML5 and is now an own spec is LocalStorage and its derivatives Session Storage or the full-fledged WebSQL and IndexedDB. Another thing is offline storage. There seems to be a huge discussion in developer circles about what to use when and if NoSQL solutions client side are the future or not. What are your thoughts? When can you use what and what are the drawbacks?
Personally I love seeing server-less applications. Looking at the storage solutions I often find it difficult to see why you wouldn’t use WebStorage every time.
In a way it acts like (in my limited experience of) NoSQL, in that you lookup a key and get a result.
Equally, I think SQL in the browser is over the top. Like you’re trying to use the storage method *you* understand and forcing it into the browser. Seems like too much work for too little win.
Offline Apps, API-wise, ie. the application cache is /really/ sexy. Like sexy with chocolate on top sexy. The idea that our applications can run without the web, or switch when it detects it’s offline is really powerful. The only problem is that the events are screwed. The event to say your app is now offline requires the user to intervene via the browser menu, telling the browser to “work in offline mode”. A total failure of experience. What’s worse is that, as far as I know, there’s no plan to make offline event fire properly :-(
That all said, cookies are definitely dead for me. I’ve yet to find a real solution for cookies since I found the Web Storage API – and there’s a good decent number of polyfills for Web Storage – so there’s really no fear of using the API.
8) Changing the track a bit, you’ve built the HTML5shiv to make HTML5elements styleable in IE. This idea sparked quite a lot of other solutions to make IE6 work with the new technologies (or actually simulate them). Where does this end? Do you think it is worth while to write much more code just to have full IE6 support?
There’s two things here:
Supporting IE6 (clue: don’t)
Polyfills
IE6, seriously, and for the umpteenth time, look at your users. Seriously. I know the project manager is going to say they don’t know what the figures are, in that case: find out! Then, once you’ve got the usage stats in hand, you know your audience and you know what technology they support.
If they’re mostly IE6 users, then adding native video with spinning and dancing canvas effect isn’t going to work – not even with shims and polyfills. IE6 is an old dog that just isn’t up to doing the mileage he used to be able to do back in his prime. But enough on this subject – the old ‘do I, or don’t I developer for IE6′ is long in the tooth.
Polyfills – that’s a different matter. They’re not there to support IE6, they’re there to bring browsers up to your expectations as a developer. However, I’d ask that you carefully consider them before pulling them in. The point of these scripts is they plug missing APIs in those older browsers. “Old browsers” doesn’t particularly mean IE6. For example, the Web Sockets API has a polyfill by way of Flash. If native Web Sockets aren’t there, Flash fills the gap, but the API is exposed in exactly the same manner, meaning that you don’t have to fork your code.
I don’t think people should be pulling in scripts just for the hell of it. You should consider what you’re trying to achieve and decide whether X technology is the right fit. If it is, and you know (or expect) your users have browsers that don’t support X technology – should you plug it with JavaScript or perhaps should you consider a different technology?
This exact same argument rings true for when someone adds jQuery just to add or remove a class from an element. It’s simply not worth it – but clearly that particular developer didn’t really understand what they needed to do. So is education the solution? I should hope so.
9) Where would you send people if they want to learn about HTML5? What are tutorials that taught you a lot? Where should interested people hang out?
I tend to also direct people to my http://html5demos.com simply to encourage viewing source, and hacking away.
Regarding what tutorials taught me – if I’m totally honest, the place I’ve learnt the most from is actually HTML5Doctor.com. There’s some pretty good JavaScript / API tutorials coming from the chaps at http://bocoup.com. Otherwise, I actually spend a lot of time just snooping through the specifications, looking for bits that I’ve not seen before and generally poking them with a stick.
10) You have announced that you are concentrating on building a framework to make Websockets easy to work with. How is that getting on and what do you see Websockets being used for in the future? In other words, why the fascination?
Concentrating is a strong word ;-) but it is true, I’ve started working on a product that abstracts Web Sockets to a service. Not the API alone, since it’s so damn simple, but the server setup: creating sessions, user control flow, waiting for users and more.
The service is called Förbind. Swedish for “connect”, ie. to connect your users. It’s still early days, but I hope to release alpha access to forbind.net this month.
I used to work in finance web sites and real-time was the golden egg: to get that data as soon as it was published. So now that it’s available in a native form in the browser, I’m all over it!
What’s more, I love the idea of anonymous users. I created a bunch of demos where the user can contribute to something without ever really revealing themselves, and when the users come, you start to see how creative people are without really trying. Sure, you get a lot of cocks being drawn, but you also see some impressive ideas – my business 404 page for example allows people to leave a drawing, one of the most impressive is a Super Mario in all his glory. Anonymous users really interest me because as grey as things can seem sometimes, a stranger can easily inspire you.
Do you know anyone I should interview for “People of HTML5″? Tell me on Twitter: @codepo8
HTML5 is a necessary evolution to make the web better. Before the HTML5 specs were created we used (and still use) a hacked together bunch of systems meant for describing and linking documents to create applications. We use generic elements to simulate rich interaction modules used in desktop development and we make assumptions as to what the user agent (browser) can do for the end user.
The good thing about this mess is that it taught us over the last few years to be paranoid in our development approach – we realised that in order to deliver working, accessible, maintainable and scalable systems we have to be professional and intelligent in our decisions and especially in our planning and architecting.
The trouble is that with the excitement around the cool new HTML5 things to play with a lot of these principles get lost and discarded as outdated. They aren’t – part of the mess that the web is in is that in 1999 a lot of people discarded everything else and instead worked only on the new hotness that was Internet Explorer 6 and DHTML. Let’s not repeat that mistake.
The two faces of HTML5 enthusiasm
Right now there are two things to get really excited about in HTML5: the richer, more meaningful semantics of new elements and the APIs that give us deep access into the workings of the browser and the operating system. The former allows us to build much richer interfaces and the latter allows us to build much more complex applications.
All of this comes with the awesome of view source (or check in development tools) for debugging. You can advocate HTML5 by writing clean and useful markup. You can kill it by treating the markup as a second class citizen which is only there to serve the script.
The markup enthusiasts are very happy about HTML5 and make it easy for people to upgrade – lots of cool new blog templates and boilerplate HTML templates are being built and polyfills created to allow using the new features and not leave behind outdated browsers.
On the app development side of things it looks much different and that is just sad. My only possible explanation is that people who come from desktop environments now tackle the HTML5 APIs without ever having to care about markup. The pragmatism of HTML5 allows a much more forgiving syntax than XHTML but it shouldn’t mean that we can just re-apply all the bad mistakes that held us back when it comes to maintenance for years.
During my career as a web developer I realised a few things make a lot of sense when building web apps:
If there is an element for a certain task – use that one. It is very likely that the element comes with accessibility and interaction features for free that you would otherwise have to simulate.
Separate CSS, JavaScript and HTML – which means it is easy to refactor your code without having to change all of them. It also means you can work in parallel with others instead of breaking each other’s code
Never rely on markup or content – as sooner or later some editing tool will come into place that messes with everything you created
This means a lot of things:
For starters it means that inline styles are simply evil as they override any settings you have in your style sheets. Only use them when this is exactly what you need to do or when you calculate them dynamically.
The same applies to inline scripting. If you have an onclick="foo()" somewhere in your HTML and foo() changes to bar() you have to rename it in every HTML document (of course nowadays it is one template, but it still means hunting down a reference you might miss)
If instead of using a native HTML element for a certain job you use SPANs and DIVs you’ll have to add classes to make them look and work – and simulate the keyboard accessibility, too.
You can’t rely on the text value of any element. A <button>edit</button> using the “edit” as the trigger for certain functionality would have to have the JS localised, too when you create the German <button>bearbeiten</button>.
Bla bla bla… C’mon Chris, it isn’t that bad!
The above best practices have been mentioned for years and a lot of people get sick of seeing them repeated. After all, this is intelligent development and standard practice in backend technologies. I came across a lot of “creative” uses lately though when doing a view-source on HTML5 demos – specifically the ones in the HTML5 advent calendar. And here is my yield of what people do.
Simulating a navigation list
One of the first things I encountered was a painting tool that had a gallery of created graphics as a background. Now, to me this would be a simple list:
This, of course is generated by the backend. My first gripe is the dropshadow image, after all this is an HTML5 showcase – just use CSS3. We also have the three instances of generated styles and double classes. Granted, an extra class gives you a handle to all images instead of tiles, so why not. But as there is no real link around the image, the click handler has to read the url from somewhere. There is a lot of unnecessary back and forth between DOM and scripting here which does slow down the whole demo. Seeing that this is also the main navigation from the entry page to the editor this could be a list inside a nav element. A list groups these items together, a bunch of DIVs doesn’t (screen readers for example tell you how many items there are in a list).
Another list I found was supposed to be links to refresh the app and have a hierarchy but instead was a flat list with classes to define hierarchy and group:
This would give you styling hooks and functionality for free. Links and buttons are great to trigger functionality – but it seems that is too easy.
Click (probably) here for functionality
If I build a button for an application to trigger a certain functionality this is the markup:
<buttontype="button"class="edit">Edit</button>
Buttons are what trigger functionality – both a backend script or a JavaScript. They are keyboard accessible, have a disabled state and sensible out-of-the-box styling that nowadays can be completely overwritten. The class can be the definition of what the button should do – instead of the text which will change. You could use an ID but a class allows to repeat buttons (for example on the top and the bottom of a results list).
The buttons I found though were slightly different:
So instead of using a nested list with classes for each button and the hierarchy in the nesting we have a lot of classes and a hand-rolled DIV construct. Instead of making buttons really disabled we rely on opacity and there is quite a mix of inline images and background images (if all were background images, they could be one sprite!). Keyboard navigation will have to be written for this and if you were to add a button you’d have to come up with another ID.
HTML5 actually has a construct for this. There is a menu element with command child elements. These are in use in Chrome’s side bar for example and should be what we use. If you want to make it work for everyone, a nested list with button elements is what to go for.
The overly complex DIV construct is quite used though – this was another example:
Talking of inline – here’s a great example of a tool generating a lot of code that could be replaced by a single event handler and event delegation:
<divid="tools"><spanonmouseout="buttonOut(1)"onmouseover="buttonOver(1)"onclick="buttonClicked(1)"id="button1"class="button"><imgalt=""src="image/button/1.png"></span><spanonmouseout="buttonOut(2)"onmouseover="buttonOver(2)"onclick="buttonClicked(2)"id="button2"class="button"><imgalt=""src="image/button/2.png"></span>
[...repeated 20 times...]
<divid="toolsSeparator"> </div><atitle=""id="toolbarButtonSave"class="toolbarButton"href="javascript:saveCanvas()"><imgalt=""src="image/save.png"></a><atitle="New"id="toolbarButtonNew"class="toolbarButton"href="javascript:newCanvas()"><imgalt="New"src="image/new.png"></a><!--[if !IE]><![IGNORE[--><!--[IGNORE[]]--><aid="toolbarButtonMenu"class="toolbarButton"onmouseout="closeMenuDelay()"onmouseover="showMenuHover()"href="javascript:showMenu()"><imgalt=">"src="image/menu.png"></a><divonmouseout="closeMenuDelay()"onmouseover="overMenu()"id="menu"><aclass="saveMenu"onmouseout="closeMenuDelay()"onmouseover="overMenu()"href="javascript:saveCanvas()">
save normal
</a><aclass="saveMenu"onmouseout="closeMenuDelay()"onmouseover="overMenu()"href="javascript:saveCanvasHi()">
save high quality
<spanclass="footnote"> (rename to *.png)</span></a><aonmouseout="closeMenuDelay()"onmouseover="overMenu()"href="javascript:showAbout()">
about...
</a><aclass="lastMenu"target="_top"onmouseout="closeMenuDelay()"onmouseover="overMenu()"href="{url}"><spanclass="footnote"><em>elsewhere: </em></span><em>a sound memory game</em></a></div><!--<![endif]--></div>
Notice that if the images for the button couldn’t be loaded for one reason or another (or you can’t see them at all) this application is very confusing indeed – no alternative text for the images and no text content to fall back to. I am also very much sure that the in and out handlers trigger visual effects CSS could handle better.
Reasons and effects
I know there are probably good reasons for all of this, and I am sure I will also do things wrongly when I am rushed or want to get things out quickly. What we have to understand though is that right now we have a responsibility to show the best of breed demos we can.
We cannot preach the open web and technologies and view-source over closed systems and at the same time forget the things we learnt in the last decade. Some of these things I found look like code Frontpage or Dreamweaver could have produced in the 90ies and resulted in a lot of badly performing, hard to maintain products that either still annoy people who have to use them or get replaced every 2 years.
We have a mandate to educate the new developers coming to the web. Unlearning something is much harder than learning it – so let’s not start with bloat and quick fixes that work but forget to advocate clean code and thinking about the impact your product has on the end users (thinking accessibility) and the poor sods that will have to maintain your product when you are gone. We are not here to advocate effects and products, we are here to promote the tools that allow anyone to easily build something cool that is also easy to understand.
HTML5 is about evolving the web as a platform – we also need to evolve with it and take more responsibility. We have app and we have markup enthusiasts. Let’s make them work together to build things that are great functionality and clean semantics.
I’ve always been a big fan of the travel/flight sequences in the Indiana Jones movies and judging by the amount of copy attempts on YouTube I am not alone in this. As I don’t own any video editing software I thought it should be possible to create the same effect with web technologies and Google Maps and lo and behold it is:
You can download the animation demo for yourself and try it out locally – all you need is a browser that supports HTML5 video. I know – the music is not quite the same as in the movies, but at least this one is not copyright infringing and it came from the heart (5 minutes in a meeting room in the Mozilla office).
So how was this done and what are problems that needed solving? Here’s how and what.
Step 1: Find the movie and get it to the right format
The MP4 format will be used by Webkit based browsers and the Ogg version by Firefox and others. As we want to control the video we omit the controls attribute on the video element – instead we create a button to play the video with JavaScript:
window.addEventListener('load',function(){var stage = document.getElementById('stage');var v = document.getElementsByTagName('video')[0];
but = document.createElement('button');
but.innerHTML='Click to see Lindbergh\'s flight';
stage.appendChild(but);
but.addEventListener('click',function(e){
v.play();
e.preventDefault();},false);},false);
As the video is markup we can do whatever we please with it – the power of open technologies. For example as we will do here we can set its opacity in CSS and put in on top of a map.
Step 3: Create the map path animation
Talking of which, let’s get that moving path done. Google Earth has an API to do that, but it needs a special plugin. Google Maps allows you to paint paths on maps (which actually are SVG, another open standard). Put that in a recursive function and you get the desired effect:
In essence, what I did was take the latitude and longitude of the start and end points and calculate as many points in between the two as I need for the duration of the animation. I store the points in an array called pos and then paint a path from the start to the current point and move the map centre to this point on every iteration.
spirit.draw=function(){var path =new google.maps.Polyline({
path:[startpos,pos[now]],
strokeColor:"#c00",
strokeOpacity: .7,
strokeWeight:10});
path.setMap(map);
map.panTo(pos[now])
now = now +1;if(now < animationend-1){
setTimeout(spirit.draw,200);}}
Check the highly commented source of the map example for the details. Now, we could use this kind of animation and play the video over it – the problem though is that they may get out of sync. When the movie stalls (as it frequently does on this hotel wireless connection) we don’t want the animation to keep moving, right?
Step 4: Syncing video and the map movement
Instead of having two sources of timing information we have to limit ourselves to one source of truth. This is the time stamp of the currently playing movie.
By the way – you might have noticed that I wrapped the map code in a tilesloaded event handler. This is another safeguard for keeping things in sync. I found that on slow connections the tile loading can delay the whole interface immensely (because of all the subdomain lookups), so I make the whole interface dependent on the loading of the map and only proceed when the tiles have finished loading. As the tilesloaded event also fires when the map pans we need to use a boolean to stop it from starting the effect several times:
google.maps.event.addListener(map,'tilesloaded',function(){if(played ===false){// [...other code...]
played =true;}});
You can read the current timestamp of a video with video.currentTime and whilst the movie is playing it constantly fires an event called timeupdate. As the event fires a lot we need to throttle it somehow. The trick here is to only take the full seconds and increase a counter when a new second is reached. You can see the timestamp and the second interval firing in the video syncing demo:
var now =0;
v.addEventListener('timeupdate',function(o){
log.innerHTML= v.currentTime;/* logging the real timestamp */var full = parseInt(v.currentTime);if(full >= now){
seqlog.innerHTML= now;/* logging the seconds firing */
now = now +1;}},false);
That way the movie can lag in between and the sequence still stays in sync. Check the source of this demo on Github.
Putting it all together
And that was about it – all I had to do is to set the movie’s opacity at a certain time stamp, start the sound at another and show and hide the copyright complaint at another. As we rely on the timestamp for the other effects we needed a boolean switch to avoid repeated firing:
And there you have it – Indiana Jones style maps using open services and open technologies. A workaround for the copyrighted audio (recorded, edited and converted with the free Audacity sound editor) and using Google’s Web Fonts as graphics.
You can now take this and change it for even more awesome:
Replace Google Maps with Openstreetmap to avoid going over the limit
Add a slight curve to the path from NYC to Paris to make it more accurate (but then again the time is not accurate either – it took charles a tad longer)
Use a static map and paint the path with Canvas to speed up and smoothen the animation
As you might know there are an incredible amount of advent calendar blogs out at the moment each delivering one cool article for each day of December until Christmas.
Today (6/12/11) two calendar blogs delivered an article of mine talking about the benefits of using local storage in browsers and how to implement it.
In essence, the article explains why it is a good idea to use local storage, explains how to use it, how to work around the issue that local storage can only store strings and gives example code on how to speed up web service use by caching information client-side much like you would do it on a server.
Have a read and go speed up your own solutions by using what browsers provide you these days.
This is a guest blog post by Chris Williams, the curator of JSConf. We are proud to support the PromoteJS campaign and hope everyone will join us to improve JS docs and make the MDN a better place for all web developers.
PromoteJS – A Worldwide Call For Improving JS Documentation Visibility
JS is not a toy language. That reality is just now reaching most developers and their first impression of JS is absolutely abysmal. Do you know what shows up when you search for “JavaScript“? The search engine results page is topped by a Wikipedia article which is shortly followed by the page for downloading Java. This is probably why so many people still unfortunately believe there is a connection between JavaScript and Java. The results for other common search terms like “Learn JS” and “JS Array” is equally as bad if not worse.
This is the first impression of JS by the general masses who are coming to this language and once you see this, you can see why people consider it a “toy language” and understand how so much bad code and disdain can exist for JS. We have hidden the better tutorials, learnings, and documentations away from ourselves AND more to the point, those trying to learn this language. New entrants struggle to learn JS, but eventually just adopt what they know from PHP, Java, Perl, Python and Ruby to a close approximation of runnable code that suffices. They then publish it back out, proud of what they have done, and continue to perpetuate this plague of improper JS coding.
We have failed our fellow designers AND developers in this sense. We have made it almost impossible to learn proper JS, a language with both beauty and warts. Some will say it is not our fault, that browser vendors should provide the API documentation for the implementation or that the standards committee should publish and market it. I am calling bullshit on that. I say that it is up to us to invite, welcome, and most importantly properly educate people looking to learn JS. We, the best and brightest of the field, have an obligation to help those who are trying to learn and understand the complexities of the language. We are the ones that benefit from it most, since those now entering the language will be either extending, morphing, or taking over the very projects we are just now starting. Regardless of library, framework, and even language — if everyone knows how to program proper JS a little better, we all win. Period.
So I challenge you to put down your library or framework preferences and write about some interesting facet about the JS language. Describe how you find the attributes on an object, what the difference between an object and an array is (and how to tell the two a part), anything and everything. If you seek fame and click traffic, write about the entry level stuff. If you seek respect and deep dialogs, write about the difference between implementations and convey the wisdom of when to favor one method over the other. If writing is too time consuming or your muse escapes you, I am announcing today a new campaign, PromoteJS. Through organic guerrilla SEO we can change how search engines present answers to common queries about our language and in doing so improve the visibility of proper educational resources. Our initial target for PromoteJS is to make the proper MDN documentation the first result for standard new JS developer queries.
In order to track our efforts, we have also released Are We First Yet which is a node.js application that tracks the search engine page rank for each of the target terms. Tracking is done on a day-over-day basis so that everyone can see the progress we have made and, if so desired to help the cause, write articles targeting the keywords. With these two efforts, we hope to enabled not just the JS community, but all developers, to improve the visibility of proper documentation. In the few days since unveiling this effort at JSConf EU, there have been millions of page views for the PromoteJS site and the button has spread like wildfire throughout the community. We have already drastically improved the rankings for key terms like “Learn JS”, “Learn JavaScript”, and “JS Documentation”, but we need your help to continue to improve all the rankings.
We need to be the voice of education for our community. We need to promote the proper way of doing things, instead of just ignoring those that don’t “get it” or watering things down. We need to commit to educating our fellow developers on JS, the language, and in doing so it helps all of our frameworks, libraries, meetups, and conferences. PromoteJS is a step in that direction, but by no means the end of the story, be sure to check the site frequently as we continue to add new ways to help improve documentation visibility and the documentation itself.
mozRequestAnimationFrame is an experimental API to make Javascript animations more efficient. We do not guarantee to support it forever, and I wouldn’t evangelize sites to depend on it. We’ve implemented it so that people can experiment with it and we can collect feedback. At the same time we’ll propose it as a standard (minus the moz prefix, obviously), and author feedback on our implementation will help us make a better standard.
This feature will be available in Firefox 4 Beta 4.
In Firefox 4 we’ve added support for two major standards for declarative animation — SVG Animation (aka SMIL) and CSS Transitions. However, I also feel strongly that the Web needs better support for JS-based animations. No matter how rich we make declarative animations, sometimes you’ll still need to write JS code to compute (“sample”) the state of each animation frame. Furthermore there’s a lot of JS animation code already on the Web, and it would be nice to improve its performance and smoothness without requiring authors to rewrite it into a declarative form.
Obviously you can implement animations in JS today using setTimeout/setInterval to trigger animation samples and calling Date.now() to track animation progress. There are two big problems with that approach. The biggest problem is that there is no “right” timeout value to use. Ideally, the animation would be sampled exactly as often as the browser is able to repaint the screen, up to some maximum limit (e.g., the screen refresh rate). But the author has no idea what that frame rate is going to be, and of course it can even vary from moment to moment. Under some conditions (e.g. the animation is not visible), the animation should stop sampling altogether. A secondary problem is that when there are multiple animations running — some in JS, and some declarative animations — it’s hard to keep them synchronized. For example you’d like a script to be able to start a CSS transition and a JS animation with the same duration and have agreement on the exact moment in time when the animations are deemed to have started. At each paint you’d also like to have them sampled using the same “current time”.
These problems have come up from time to time on mailing lists, for example on public-webapps. A while ago I worked out an API proposal and Boris Zbarsky just implemented it; it’s in Firefox 4 beta 4. Here’s the API, it’s really simple:
window.mozRequestAnimationFrame(): Signals that an animation is in progress, requests that the browser schedule a repaint of the window for the next animation frame, and requests that a MozBeforePaint event be fired before that repaint.
The browser fires a MozBeforePaint event at the window before we repaint it. The timeStamp attribute of the event is the time, in milliseconds since the epoch, deemed to be the “current time” for all animations for this repaint.
There is also a window.mozAnimationStartTime attribute, also in milliseconds since the epoch. When a script starts an animation, this attribute indicates when that animation should be deemed to have started. This is different from Date.now() because we ensure that between any two repaints of the window, the value of window.mozAnimationStartTime is constant, so all animations started during the same frame get the same start time. CSS transitions and SMIL animations triggered during that interval also use that start time. (In beta 4 there’s a bug that means we don’t quite achieve that, but we’ll fix it.)
That’s it! Here’s an example; the relevant sample code:
It’s not very different from the usual setTimeout/Date.now() implementation. We use window.mozAnimationStartTime and event.timeStamp instead of calling Date.now(). We call window.mozRequestAnimationFrame() instead of setTimeout(). Converting existing code should usually be easy. You could even abstract over the differences with a wrapper that calls setTimeout/Date.now if mozAnimationStartTime/mozRequestAnimationFrame are not available. Of course, we want this to become a standard so eventually such wrappers will not be necessary!
Using this API has a few advantages, even in this simple case. The author doesn’t have to guess a timeout value. If the browser is overloaded the animation will degrade gracefully instead of uselessly running the step script more times than necessary. If the page is in a hidden tab, we’ll be able to throttle the frame rate down to a very low value (e.g. one frame per second), saving CPU load. (This feature has not landed yet though.)
One important feature of this API is that mozRequestAnimationFrame is “one-shot”. You have to call it again from your event handler if your animation is still running. An alternative would be to have a “beginAnimation”/”endAnimation” API, but that seems more complex and slightly more likely to leave animations running forever (wasting CPU time) in error situations.
This API is compatible with browser implementations that offload some declarative animations to a dedicated “compositing thread” so they can be animated even while the main thread is blocked. (Safari does this, and we’re building something like it too.) If the main thread is blocked on a single event for a long time (e.g. if a MozBeforePaint handler takes a very long time to run) it’s obviously impossible for JS animations to stay in sync with animations offloaded to a compositing thread. But if the main thread stays responsive, so MozBeforePaint events can be dispatched and serviced between each compositing step performed by the compositing thread, I think we can keep JS animations in sync with the offloaded animations. We need to carefully choose the animation timestamps returned by mozAnimationStartTime and event.timeStamp and dispatch MozBeforePaint events “early enough”.
A few people have been playing with mozRequestAnimationFrame and noticed that they can’t get more than 50 frames per second. This is intentional, and it’s a good feature.
On modern systems an application usually cannot get more than 50-60 frames per second onto the screen. There are multiple reasons for this. Some of them are hardware limitations: CRTs have a fixed refresh rate, and LCDs are also limited in the rate at which they can update the screen due to bandwidth limitations in the DVI connector and other reasons. Another big reason is that modern operating systems tend to use “compositing window managers” which redraw the entire desktop at a fixed rate. So even if an application updates its window 100 times a second, the user won’t be able to see more than about half of those updates. (Some applications on some platforms, typically games, can go full-screen, bypass the window manager and get updates onto the screen as fast as the hardware allows, but obviously desktop browsers aren’t usually going to do that.)
So, firing a MozBeforePaint event more than about 50 times a second is going to achieve nothing other than wasting CPU (i.e., power). So we don’t. Apart from saving power, reducing animation CPU usage helps overall performance because we can use the free time to perform garbage collection or other house-cleaning tasks, reducing the incidence or length of frame skips.
We need to do some followup work to make sure that on each platform we use the optimal rate; modern platforms have APIs to tell us the window manager’s composition rate. But 50Hz is almost always pretty close.
This all means that measuring FPS is a bad way to measure performance, once you’re up to 50 or more. At that point you need to increase the difficulty of your workload.