Skip to content

Blogs

CSS media queries in JavaScript, Part 2

NCZOnline - Nicholas C. Zakas - Thu, 01/19/2012 - 17:30

In my previous post[1], I introduced using CSS media queries in JavaScript both through a custom implementation and using the CSSOM Views matchMedia() method. Media queries are incredibly useful, both in CSS and JavaScript, and so I continued with my research to see how best to take advantage of this capability. As it turns out, the matchMedia() method has a few interesting quirks that I didn’t realize when I wrote the first part of this series.

matchMedia() and its quirks

Recall that matchMedia() returns a MediaQueryList object that allows you to determine whether or not the given media type matches the current state of the browser. This is done using the matches property, which returns a boolean. As it turns out, matches is a getter, which requeries the state of the browser each time it’s called:

var mql = window.matchMedia("screen and (max-width:600px)");
console.log(mql.matches);

//resize the browser

console.log(mql.matches);  //requeries

This is actually really useful, because it allows you to keep a reference to a MediaQueryList object and repeatedly check the state of the query against the page.

Chrome and Safari have a weird behavior, though. The initial value for matches is always correct but doesn’t get updated by default unless the page has a media block defined with the same query and at least one rule (hat tip: Rob Flaherty[2]. For instance, in order for a MediaQueryList representing “screen and (max-width:600px)” to update appropriately (including firing events), you must have something like this in your CSS:

@media screen and (max-width:600px) {
    .foo { }
}

There needs to be at least one rule in the media block, but it doesn’t matter if that rule is empty. As long as this exists on the page then the MediaQueryList will be updated appropriately and any listeners added via addListener() will fire when appropriate. Without this media block on the page, the MediaQueryList acts like a snapshot of the page state at its creation time.[3]

You can fix this by adding a new rule using JavaScript:

var style = document.createElement("style");
style.appendChild(document.createTextNode("@media screen and (max-width:600px) { .foo {} }"));
document.head.appendChild(style);    //WebKit supports document.head

Of course, you would need to do that for every media query being accessed using matchMedia(), which is a bit of a pain.

There is also a strange quirk in Firefox’s implementation. In theory, you should be able to assign a handler for when the query state changes and not keep a reference to the MediaQueryList object, such as:

//doesn't quite work in Firefox
window.matchMedia("screen and (max-width:600px)").addListener(function(mql) {
     console.log("Changed!");
});

When this pattern is used in Firefox, the listener may never actually be called even though the media query has become valid. In my tests, it would fire between 0 and 3 times, and then never again. The Firefox team has acknowledged this is a bug[4] and should hopefully be fixed soon. In the meantime, you need to keep the MediaQueryList reference around to ensure your listeners fire:

//fix for Firefox
var mql = window.matchMedia("screen and (max-width:600px)");
mql.addListener(function(mql) {
     console.log("Changed!");
});

The listener here will continue to be called as long as there is a reference to the mql object.

More on listeners

My initial description of the media query listeners in my previous post was incomplete due to a misunderstanding on my part. The listeners are actually trigger in two instances:

  1. When the media query initially becomes valid. So in the previous example, when the screen becomes 600 pixels wide or less.
  2. When the media query initially becomes invalid. For example, when the screen becomes wider than 600 pixels.

This behavior is why the MediaQueryList object is passed into the listener, so you can check matches to determine if the media query just became valid or not. For example:

mql.addListener(function(mql) {
    if (mql.matches) {
        console.log("Matches now!");
    } else {
        console.log("Doesn't match now!");
    }
});

Using code like this, you can monitor when a web application moves into and out of certain states, allowing you to alter the behavior accordingly.

To polyfill or not?

When I first looked at matchMedia(), I did so with the intent of creating a polyfill. Paul Irish[5] implemented a polyfill using a technique similar to the one I described in my last post (and gave me credit for it, thanks Paul!). Paul Hayes then forked[6] his work to create a polyfill with rudimentary listener support based on a very ingenuous use of CSS transitions to detect changes. However, as it relies on CSS transitions, the listener support is limited to browsers with CSS transition support. That, coupled with the fact that calling matches doesn’t requery the browser state, and the bugs in both Firefox and WebKit, led me to believe that building a polyfill wasn’t the right approach. After all, how can you polyfill appropriately when there are such obvious bugs in the real implementations that need fixing?

My approach was to create a facade to wrap this behavior in an API where I could smooth out the issues. Of course, I chose to implement the API as a YUI Gallery module[7] called gallery-media. The API is very simple and consists of two methods. The first is Y.Media.matches(), which takes a media query string and returns true if the media matches and false if not. No need to keep track of any objects, just get the info:

var matches = Y.Media.matches("screen and (max-width:600px)");

The second method is Y.Media.on(), which allows you to specify a media query and a listener to call when the media query becomes valid or invalid. The listener is passed an object with matches and media properties to give you information about the media query. For example:

var handle = Y.Media.on("screen and (max-width:600px)", function(mq) {
    console.log(mq.media + ":" + mq.matches);
});

//detach later
handle.detach();

Instead of using CSS transitions to monitor for changes, I use a simple onresize event handler. On the desktop, the size of the browser window is the main thing that will change (as opposed to mobile devices, where the orientation may also change), so I made this simplifying assumption for older browsers. The API uses the native matchMedia() functionality where available and patches up the differences in WebKit and Chrome so that you get consistent behavior.

Conclusion

CSS media queries in JavaScript are a bit more complicated than I first expected, but still quite useful. I don’t think it’s appropriate to polyfill matchMedia() giving the strange bugs that are still abound, effectively preventing you from even using the native code the same way across browsers. A facade, on the other hand, insulates you from the bugs and changes that are likely to occur going forward. Now go forth and use CSS media queries to their potential…in JavaScript.

References
  1. CSS media queries in JavaScript, Part 1 by me
  2. Rob Flaherty’s tweet
  3. matchMedia() MediaQueryList not updating
  4. matchMedia() listeners lost
  5. matchMedia polyfill by Paul Irish
  6. matchMedia polyfill by Paul Hayes
  7. YUI 3 Gallery Media module by me
Categories: Blogs

Book review: The Tangled Web

NCZOnline - Nicholas C. Zakas - Tue, 01/17/2012 - 17:30

The Tangled WebI’m not really sure what I was expecting from The Tangled Web: A Guide to Securing Modern Web Applications. Having learned more about web security in the past year, I suppose I was hoping for a more in-depth treatment of common web application security issues. In my mind, I pictured a chapter on Cross-Site Scripting attacks and mitigation steps, a chapter on Cross-Site Request Forgery and what to do about it, etc. Instead, the book tackles the security problem with an exhaustive and dry examination of all the technologies that make up the web. Though interesting technically, it’s very easy to get lost in these details and end up at the other end unsure of how the description relates to real-world security issues.

For instance, the author goes into how a URL is parsed and the differences between how different browsers parse URLs. That’s interesting information, but I’m still not sure what type of attacks I should look out due to these issues and how to address them if they do occur. The same treatments are given to HTTP itself, HTML, CSS, JavaScript, and other parts of web application stack.

One of the most frustrating aspects of this book is how browser names are frequently thrown around without version numbers. Saying “Internet Explorer” does something leaves me wondering if that was one of the many issues fixed in Internet Explorer 9 and 10 or not. While it’s fine to leave off version numbers when discussing Chrome, Internet Explorer just has far too many differences to make this useful.

I found the code examples to be incredibly terse, and in some cases missing completely. Case in point, a discussion of the sandbox attribute for <iframe> doesn’t have a single code example showing its proper usage. Certainly property usage is part of ensuring security. Other sections of the book suffer from the same code-terseness to its detriment. A lot of the topics could stand more actual examples.

Which brings me to my overall issue with the book: it reads more like it was written by a researcher for a researcher. This really isn’t a book to help you solidify your web application security. In fact, I’m not sure I picked up any new techniques from reading the book at all. My head is now filled with trivia knowledge about web browsers that I’m unable to practically apply to my work, which is frustrating. The only attempt the author makes at giving actionable advice is on the “checklist” at the end of each chapter. The checklist contains way-too-terse descriptions of how to mitigate certain attacks…but without practical code examples, the bullet points are quite lost.

This book seems mostly targeted at amateur security professional who need a good brain dump on all the various flaws in internet protocols and technologies in order to get their feet wet. It’s definitely not for web developers looking to improve their web application security, making the subtitle, “A Guide to Securing Modern Web Applications”, a complete misnomer. If anything, it’s a guide through current web technologies showing you that the internet is a mess and leaving you to wonder how to fix it.

I really, really wanted to like this book, but unfortunately, I just didn’t find it practical enough to recommend it as guide for most web developers. If you don’t understand security issues at all, then this is probably a good book to pick up, but otherwise, you’ll need to go elsewhere to find practical advice.

Categories: Blogs

Now available: Professional JavaScript, 3rd Edition

NCZOnline - Nicholas C. Zakas - Mon, 01/09/2012 - 21:48

Professional JavaScript, 3rd EditionI’m very excited to announce that Professional JavaScript for Web Developers, 3rd Edition is now shipping and available in bookstores. Over six years, the first edition was released and it changed my life in ways I never could have anticipated. It was through this book that I ended up at Yahoo! and was invited to speak at conferences for the first time. The first edition was a labor of love and that love has continued over the years through the second edition and into this one, which took over a year to complete.

Those who know me shouldn’t be surprised that this book is more than just an update. The 3rd edition features five completely new chapters covering the new HTML5 APIs such as history state managements, canvas, offline applications, web workers, and more. Throughout the book, I’ve added references to changes in ECMAScript 5, including how strict mode works and how to use the new object-creation APIs. All of the existing chapters were also updated with the latest browser support information including mobile support (sadly, that will always be a bit out-of-date). A special appendix about ECMAScript Harmony is also included to give you a taste of the future.

I’m also incredibly honored to have a foreword written by Rey Bango. Rey had so many kind words about the 2nd edition that I was thrilled when he agreed to write the foreword for this one. And here it is:

I look back at my career (now 20+ years) and in between coming to the realization that my grey hairs
have really sprouted out, I reflect on the technologies and people that have dramatically affected
my professional life and decisions. If I had to choose one technology, though, that has had the single
biggest positive influence on me, it would be JavaScript. Mind you, I wasn’t always a JavaScript believer.
Like many, I looked at it as a play language relegated to doing rotating banners and sprinkling some
interesting effects on pages. I was a server-side developer and we didn’t play with toy languages, damn
it! But then something happened: Ajax.

I’ll never forget hearing the buzzword “Ajax” all over the place and thinking that it was some very cool,
new and innovative technology. I had to check it out and as I read about it, I was floored when I realized
that the toy language I had so readily dismissed was now the technology that was on the lips of every
professional web developer. And suddenly, my perception changed. As I continued to explore past what
Ajax was, I realized that JavaScript was incredibly powerful and I wanted in on all the goodness it had to
offer. So I embraced it wholeheartedly working to understand the language, joining the jQuery project
team and focusing on client-side development. Life was good.

The deeper I became involved in JavaScript, the more developers I met, some whom to this day I still
see as rockstars and mentors. Nicholas Zakas is one of those developers. I remember reading the second edition of this very book and feeling like, despite all of my years of tinkering, I had learned so much.
And the book felt genuine and thoughtful, as if Nicholas understood that his audience’s experience
level would vary and that he needed to manage the tone accordingly. That really stood out in terms of
technical books. Most authors try to go into the deep-dive techno-babble to impress. This was different
and it immediately became my go-to book and the one I recommended to any developer that wanted
to get a solid understanding of JavaScript. I wanted everyone to feel the same way I felt and realize how
valuable a resource it is.

And then, at a jQuery conference, I had the amazing fortune of actually meeting Nicholas in person.
Here was one of top JavaScript developers in the world working on one of the most important web
properties in the world (Yahoo!) and he was one of the nicest people I had ever met. I admit, I was a bit
starstruck when I met him and the great thing is that he was just this incredibly down-to-earth person
who just wanted to help developers be great. So not only did his book change the way I thought about
JavaScript, Nicholas himself was someone that I wanted to continue to work with and get to know.

When Nicholas asked me to write this foreword, I can’t explain how flattered I was. Here I am being the
opening act for the guru. It’s a testament to how cool of a person he is. Most importantly though, it
gives me an opportunity to share with you why I felt this book is so important. I’ve read many JavaScript
books and there are certainly awesome titles out there. This book, though, offers in my opinion the total
package to make you an incredibly proficient and able JavaScript developer. The smooth and thoughtful
transition from introductory topics such as expressions and variable declarations to advanced topics
such as closures and object-oriented development is what sets it apart from other books that are either
too introductory or expect that you’re already building missile guidance systems with JavaScript. It’s
the “every man’s” book that will help you write code that you’ll be proud of and build websites that will
excite and delight.

Rey Bango
Sr. Technical Evanglist, Microsoft Corporation
jQuery Project Team

I hope that Rey, and all of you, enjoy the 3rd edition just as much as (if not more than) the 2nd edition. The book is available for purchase at Amazon and available for download as an ebook from Wrox.

Categories: Blogs

Clientcide 3.0.10

Clientcide - Aaron Newton - Fri, 01/06/2012 - 19:03
Another maintenance release for the most part. What’s new? Clientcide: * StickyWin.Ajax now can cache requests (useful for tips and whatnot); thanks @zipz * New class: StickyWin.PointyTip.Ajax – provides for ajax tips. Again, thanks @zipz * Fixed errant reference to old Browser property. This was breaking when used with MooTools 1.4* w/o compat. * Tabswapper now allows you to specify [...]
Categories: Blogs

CSS Lint v0.9.2 now available

NCZOnline - Nicholas C. Zakas - Thu, 01/05/2012 - 19:42

A new version of CSS Lint is now available both on csslint.net and through npm for NodeJS. Version 0.9.2 focused on improving validation support (full support is planned for v1.0.0) and stability. As part of that, 0.9.1 and 0.9.2 were quickly rolled out after 0.9.0 to address some flaws in the validation logic.

Other changes for this release:

  • Dino Chiesa submitted a Windows Script Host (WSH) CLI.
  • There were a couple of parser compatibility bugs that were fixed.
  • Various rules regarding vendor prefixed properties were updated to reflect Internet Explorer 10.
  • New Rule: The fallback-colors rule was suggested by Dustin Cass and warns when a CSS3 color is used without a CSS2 fallback (rule documentation)
  • New Rule: The duplicate-background-images was created by Hans-Peter Buniat and warns when a background image is used more than once ((rule documentation)

Thanks once again to the CSS Lint community for continuing to file bugs and make feature requests. We’re rapidly approaching and very stable v1.0.0 release due to your participation and feedback. Keep it coming!

Categories: Blogs

Proposal: Scripting detection using CSS media queries

NCZOnline - Nicholas C. Zakas - Wed, 01/04/2012 - 20:41

I’ve been doing a lot of thinking about CSS media queries lately. I’m a big fan of media queries, as I think they bring a sense of sanity to feature detection. That’s a big reason why I was investigating CSS media queries in JavaScript[1] and will continue to do so. I think we’re only scraping the surface of what can be done with media queries on the web. As part of my pondering over the holiday break, I scribbled down a few notes of ways I’d like to use media queries. I just proposed the first one to the CSS working group.

The Proposal

Yesterday, I sent an email[2] to the CSS working group with my proposal. The basic idea is to allow you to determine if scripting is enabled in the browser using a media query. The proposal can be summed up with a few examples:

@media screen and (script) {
    /* styles to apply only when scripting is enabled */
}

@media screen and not (script) {
    /* styles to apply only when scripting is disabled */
}

So, just like you currently use device-width, orientation, and so on to detect features of the device, you could also use script in the same way.

Rationale

In the realm of progressive enhancement, you don’t want to show page elements that can’t be used. This may be as simple as an arrow next to link indicating a dropdown menu is available. If JavaScript is disabled, you want the link to act like a regular link and not confuse people by having an arrow that means nothing. So you want to apply the style that shows the arrow only if JavaScript is enabled.

The most common approach to this problem is to add a class to the <html> element via JavaScript. So somewhere on the page, you put:

<script>
document.documentElement.className += " js-enabled";
</script>

This adds the class js-enabled via JavaScript. Of course, this only gets executed when JavaScript is enabled. You can then define CSS rules such as:

.arrow {
    /* empty */
}

.js-enabled .arrow {
    background: url(image.png) no-repeat;
}

It’s a bit of a hack, but this basic technique is in use by large sites such Twitter and the Yahoo! homepage, as well as being done automatically by Modernizr and YUI.

While this technique works, it has two downsides. First, you need to include that little JavaScript snippet (or a supporting library) to ensure the class ends up being added. Second, it alters the specificity of your rules, which can adversely affects the cascade.

Clarifications

I’m a big believer that common patterns should be codified and standardized so that the development community can move on to more interesting challenges[3]. As such, it seems that the community has spoken that we want to define different styles when JavaScript is enabled, and CSS media queries seem like the right approach.

The CSS Media Queries specification[4] states:

A media query consists of a media type and zero or more expressions that check for the conditions of particular media features. Among the media features that can be used in media queries are ‘width’, ‘height’, and ‘color’. By using media queries, presentations can be tailored to a specific range of output devices without changing the content itself.

The term media feature is key. When I was first debating myself over whether scripting support is appropriate for a CSS media query, I went and read the specification. Script support is just as much a media feature as color depth and orientation. It’s a capability of that particular device at the time your page is loaded. Given that, I felt comfortable proposing the inclusion of script as another media feature to test.

To be clear, my proposal’s goal is to easily indicate whether or not scripting is enabled in a browser. Think of it as a relative of the <noscript> element. So instead of doing something like this:

<noscript>
<style>
.foo {
    color: red;
}
</style>
</noscript>

You could do this:

@media screen and not (script) {
    .foo {
        color: red;
    }
}

Of course, by omitting not, you could also apply changes when scripting is enabled.

Some non-goals of this proposal are:

  • Replacing JavaScript feature detection. You will still be checking, in JavaScript, if certain features are available. In short: I’m not looking to propose implementing media query features for all possible JavaScript APIs. If you want that, you should use Modernizr.
  • Enabling JavaScript in CSS. I have no desire to have JavaScript in CSS in any way, shape, or form.
  • Be JavaScript-centric in detection. Actually, the intent is to indicate if scripting is enabled, not just JavaScript. It would probably be easy to extend the syntax, such as (script:"text/javascript"), but I’m not sure that’s necessary at this point.

And as I always like to remind people: no one would force you to use this feature if it’s implemented. If you don’t like it, you can always leave it to those who do.

Conclusion

I think CSS media queries are one of the best things to happen to the web, and I look forward to using them in new and interesting ways. Adding feature detection for scripting seems like a logic step towards standardizing a fairly common practice. The good news is that Florian Rivoal, one of the editors of the CSS Media Queries specification has agreed[5] to write it up as a proposal for inclusion in CSS Level 4 Media Queries. I hope the proposal is able to move forward quickly.

References
  1. CSS media queries in JavaScript, Part 1 by me
  2. Proposal: Detecting JavaScript with media queries by me
  3. When web standards fail us by me
  4. CSS Level 3 Media Queries
  5. Re: Proposal: Detecting JavaScript with media queries by Florian Rivoal
Categories: Blogs

CSS media queries in JavaScript, Part 1

NCZOnline - Nicholas C. Zakas - Tue, 01/03/2012 - 17:30

Early in 2011, I was working on a project where I was doing some feature detection in JavaScript. Some tinkering led to the thought that using a CSS media query would work much better and so I spent some time coming up with a function to use CSS media queries in JavaScript. My thought process was simple: if I’m only applying certain CSS based on a media query, I also only want to run certain JavaScript based on a media query. The result was the following function, which I first published as a Gist[1] last March:

var isMedia = (function(){

    var div;

    return function(query){

        //if the <div> doesn't exist, create it and make sure it's hidden
        if (!div){
            div = document.createElement("div");
            div.id = "ncz1";
            div.style.cssText = "position:absolute;top:-1000px";
            document.body.insertBefore(div, document.body.firstChild);
        }

        div.innerHTML = "_<style media=\"" + query + "\"> #ncz1 { width: 1px; }</style>";
        div.removeChild(div.firstChild);
        return div.offsetWidth == 1;
    };
})();

The idea behind this function is pretty simple. I create a <style> node with a media attribute equal to the one I’m testing. Inside, there’s a CSS rule applied to a <div> and all I have to do is check to see if the style has been applied. I wanted to avoid browser detection, so instead of using currentStyle and getComputedStyle(), I decided to just change the width of an element and check it using offsetWidth.

Very quickly, I had a version of this function that worked in almost all browsers. The exceptions, as you may have guessed, were Internet Explorer 6 and 7. In those browsers, the <style> element is considered a NoScope element[2]. NoScope elements were a horrid exception to what happens when HTML is injected into a page using innerHTML or any other means. All NoScope elements are effectively dropped if they are the first element added as an HTML string. In order to use a NoScope element, you must be sure that it’s not the first part of an HTML string. Thus, I put the underscore in before the <style> element and then remove it – tricking Internet Explorer 6 and 7 into applying the element as it should. Other browsers don’t have this NoScope element issue, but using this technique doesn’t negatively effect them (as I said before, I was trying to avoid browser detection).

In the end, you can use the function like this:

if (isMedia("screen and (max-width:800px)"){
    //do something for the screen
}

if (isMedia("all and (orientation:portrait)")){
    //react to portrait mode
}

The isMedia() worked great in all browsers I tested (back to Internet Explorer 6) in that it accurately detects whether the browser thinks the media query is valid. So passing in an unsupported query to any browser always returns false. Internet Explorer 6, for instance, returns true if you use “screen”, but anything more complex and it returns false. I thought this was acceptable because any CSS in other media queries wouldn’t be applied in that browser anyway.

CSSOM View

The CSS Object Model (CSSOM) Views specification[3] adds native support for CSS media queries in JavaScript by adding a method, matchMedia(), to the window object. You pass in a CSS media query and receive back a MediaQueryList object. The object contains two properties: matches, which is a boolean value indicating if the CSS media query matches the current view state, and media, which is the same string that was passed in. For example:

var match = window.matchMedia("screen and (max-width:800px)");
console.log(match.media);     //"screen and (max-width:800px)"
console.log(match.matches);   //true or false

So far, this API doesn’t provide much more than my Gist. You may be wondering, though, why does matchMedia() return an object? After all, if the media doesn’t match, of what use is it? The answer is in two methods: addListener() and removeListener().

These two methods allow you to interact with view state changes based on CSS media queries. For instance, maybe you want to be alerted when a tablet is switched to portrait mode. You could do something like this:

var match = window.matchMedia("(orientation:portrait)");
match.addListener(function(match){
    if (match.media == "(orientation:portrait)") {
        //do something
    }
});

This code adds a listener for a media query. When the query becomes true for the current view state, the listener is executed and the corresponding MediaQueryList object is passed in. In this way, you can have your JavaScript be just as responsive as your layout without polling. So unlike my Gist, this API allows you to monitor the changing view state and adapt the interface behavior accordingly.

The matchMedia() method is available in Chrome, Safari 5.1+, Firefox 9+, and Safari for iOS 5+. These represent the browsers that I have access to and can verify. Internet Explorer and Opera still don’t support matchMedia() as of their latest versions.

Note: The WebKit implementation is a bit buggy, so matches doesn’t update after the MediaQueryList object is created and query listeners don’t fire. Hopefully this will be fixed soon.

Conclusion

CSS media queries bring a simple feature detection syntax to both CSS and JavaScript. I expect that media queries will become a big part of JavaScript coding in the future, alerting developers as to when significant interface changes occur. There is no reason that the behavior of a web application shouldn’t be just as responsive as the layout, and CSS media queries give us that power today.

References
  1. A function for detecting if the browser is in a given media mode
  2. MSDN: innerHTML Property
  3. CSS Object Model View
  4. matchMedia() MediaQueryList is not updating
Categories: Blogs

Crocodile Cage Diving - Darwin, Australia

Not Dennis Byrne - Mon, 01/02/2012 - 22:17
Crocodile cage diving in Darwin, Australia ...

Categories: Blogs

Cage Diving with Great White Sharks - Neptune Islands, Australia

Not Dennis Byrne - Mon, 01/02/2012 - 21:56
My favorite shots from cage diving ...

Categories: Blogs

JavaScript as a First Language

John Resig - Blog - Wed, 12/21/2011 - 21:04

At Khan Academy we've been investigating teaching Computer Science to students in some new and interesting ways. The most interesting aspect of which is that we're likely going to be teaching them JavaScript as their first language.

We're in a very unique position as we're primarily aiming to teach students who've been through our previous math and science-centric curriculum. Because of this we can create some rather compelling exercises and projects that never would've been feasible otherwise.

The prospect of teaching the JavaScript language as a first language is actually really exciting. Teaching prototypal inheritance to experienced classical-inheritance-using developers is normally rather frustrating (and results in many libraries springing up attempting to replicate the classical style of inheritance in JavaScript, which is a whole realm of weirdness in-and-of itself). Teaching prototypal inheritance to someone who has never seen any form of inheritance before will decidedly be an easier task. The same goes for learning functional programming. JavaScript is a great language for experiencing functional programming and can be a major focus of our curriculum as a result.

As we've begun to look at the prospect of JavaScript-as-a-first-language a number of obvious warts stick out (as is obvious to anyone who has worked with JavaScript for any duration). To make sure that general warts don't crop up we will be using some form of linting (either JSLint or JSHint or similar) in the code editor to give the users contextual information on what's happening with their code and why they should be writing their code in a certain way.

We want to go beyond basic syntax tweaks though and find ways of using the language that'll result in an easier learning experience. In particular there are two changes which will likely result in a much simpler on-ramp to learning.

Note: These particular recommendations really only make sense if you're teaching JavaScript to someone who has never seen the language before and is really only programming with a set of specific, well-coded, libraries. Obviously more will have to be taught in order bring the students up to the level of "see any random piece of cross-browser JavaScript code and understand what it does."

Type Coercion

Type coercion is just a complete mess, as many many others have pointed out and as what Douglas Crockford typically teaches, as in JavaScript: The Good Parts.

It might make sense to discuss it far later in the education cycle... like after learning about prototypes, functional programming, and closures. Basically after everything that's actually important.

name === "John"

The first change that I'm recommending is that the students will only ever see, and use, === (and !==). While using '==' does have the advantage of being syntactically shorter there is so much type coercion baggage attached to it as to make it an exercise in futility to try and teach early on in the learning of programming.

The one exception that might be worthwhile to teach later on is the case in which you wish to see if a variable contains a null or undefined value. This can be done easily with a simple someVar == null check and is likely the one useful case of ==. (Another noted exception is the browser bug in IE where === checks against Window objects will always return false, but it's unlikely that we'll cover such specific browser issues in our curriculum.)

Falsy Values

For the same reasons that == can be messy, so can falsy values. Enforcing strict boolean checks would result in less edge cases but would certainly result in longer code. Perhaps education of falsy values can be limited to booleans, null, and undefined with number and string falsy values left for a later exercise.

Function Declarations

Perhaps the most interesting change that we can make is a rather subtle one, but it's eschewing normal function declarations for creating anonymous functions and assigning them to a variable.

// Don't do this:
function getData() { }

// Do this instead:
var getData = function() { };

There are a number of good habits that are instilled when you use this particular technique.

  • Makes it easier to understand "functions as an object". I've found that when you show new developers a function being assigned to a variable it suddenly becomes much more obvious that a function is actually an object and can be manipulated as such (and that a function can be passed as an argument to another function). Thus students are advanced along the path towards a better understanding of functional programming.
  • It enforces good semicolon habits. Traditional function declaration is the only situation in which semicolons aren't needed (save for conditional statements and loops, naturally) and it makes it much more obvious when they're required all the time.
  • Doesn't have much of the baggage traditionally associated with functions and scope.
Block Scope

This is the remaining area that'll certainly be a challenge for any introductory student to understand and yet I don't see a particularly good solution here. The issue of variables declared within for loops hoisting up is more than enough to make most developers heads spin. I'll have to see if we can't come up with some intuitive ways of explaining how variable declaration works (and combining it with vigilant lint enforcement) rather than having a purely technical solution.

(While (function(){ ... })(); is a solution I'm skeptical that we'll be able to teach that early-enough on as to make it worthwhile.)

JavaScript as a First Language

It should be noted that while we're starting with JavaScript as a first language - largely due to its ubiquity, desirability in the larger workforce, lack of prior installation requirements, and ability to create something that's easy to share with friends - we're not going to be myopic and only focus on JavaScript. There are so many things that can be learned from other languages, not to mention entire skillsets that aren't terribly relevant to in-browser JavaScript, that it behooves us to try and bring as much of them into our curriculum as possible.

I talk a little bit more about our choice to use JavaScript and some of the browsers that we'll want to support in our development in the following video:

By all accounts I want to try and avoid any features that would cause cross-browser weirdness to spring up. As a result we'll be making extensive use of libraries (for drawing to a canvas or manipulating the DOM) and using only JavaScript language features that work consistently in the browsers that we end up supporting.

Categories: Blogs

Introducing Props2Js

NCZOnline - Nicholas C. Zakas - Tue, 12/20/2011 - 18:02

One of my principles of Maintainable JavaScript[1] is to separate your configuration data from your application logic. Configuration data is hardcoded information that your JavaScript uses to work properly. This could be anything such as a URL or a UI string. For example:

function validate(value) {
    if (!value) {
        alert("Invalid value");
        location.href = "/errors/invalid.php";
    }
}

function toggleSelected(element) {
    if (hasClass(element, "selected")) {
        removeClass(element, "selected");
    } else {
        addClass(element, "selected");
    }
}

There are three pieces of configuration data in this code. The first is the string, “Invalid value”, which is displayed to the user. As a UI string, there’s a high chance that it will change frequently. The second is the URL “/errors/invalid.php”. URLs tend to change as development progresses due to architectural decisions. The third is the CSS class name “selected”. This class name is used three times, meaning that a class name change requires changes in three different places, increasing the likelihood that one will be missed.

Configuration data is best extracted from the core application logic, such as:

//Configuration data externalized
var config = {
    MSG_INVALID_VALUE:  "Invalid value",
    URL_INVALID:        "/errors/invalid.php",
    CSS_SELECTED:       "selected"
};

function validate(value) {
    if (!value) {
        alert(config.MSG_INVALID_VALUE);
        location.href = config.URL_INVALID;
    }
}

function toggleSelected(element) {
    if (hasClass(element, config.CSS_SELECTED)) {
        removeClass(element, config.CSS_SELECTED);
    } else {
        addClass(element, config.CSS_SELECTED);
    }
}

This example stores all of the configuration data in the config object. Each property of config holds a single piece of data, and each property name has a prefix indicating the type of data (MSG for a UI message, URL for a URL, and CSS for a class name). The naming convention is, of course, a matter of preference. The important part of this code is that all of the configuration data has been removed from the functions, replaced with placeholders from the config object.

Externalizing the configuration data means that anyone can go in and make a change without fear of introducing an error in the application logic. It also means that the entire config object can be moved into its own file, so edits are made far away from the code that uses the data.

Having an external object managing your configuration data is a good start, but I’m not a fan of storing configuration data directly in JavaScript code. Because such data changes frequently, I prefer to keep it in a simpler file format – one that’s free from worries about missing a semicolon or comma. And that’s when I turned to the Java properties file[2].

Java properties files are incredibly simple. One name-value pair per line and comments begin with a #. It’s really hard to mess up this format. Here’s what the previous example’s configuration data looks like in a Java properties file:

# UI Strings
MSG_INVALID_VALUE = Invalid value

# URLs
URL_INVALID = /errors/invalid.php

# CSS Classes
CSS_SELECTED = selected

Even though I had my configuration data in a Java properties file, I had no easy way of making this data available to JavaScript.

This is why I created Props2Js[3], a simple tool that does just one thing: reads a Java properties file and outputs it in a format that JavaScript can use. Actually, it’s capable of outputting the data into three formats that JavaScript can use: JSON, JSONP, and regular JavaScript.

java -jar props2js-0.1.0.jar --to jsonp --name myfunc --output result.js source.properties

The --to option specifies the output format, either “js”, “json”, or “jsonp”. The --name option specifies either the variable name (for “js”) or the function name (for “jsonp”); this option is ignored for “json”. The --output option specifies the file to write the data into. So this line takes the Java properties file named source.properties and outputs JSONP with a callback function of myfunc to a file named result.js.

Props2Js outputs the properties file mentioned above into JSON format:

{"MSG_INVALID_VALUE":"Invalid value","URL_INVALID":"/errors/invalid.php",
"CSS_SELECTED":"selected"}

Here’s the JSONP output:

myfunc({"MSG_INVALID_VALUE":"Invalid value","URL_INVALID":"/errors/invalid.php",
"CSS_SELECTED":"selected"});

And here’s the plain JavaScript option with --name config:

var config={"MSG_INVALID_VALUE":"Invalid value","URL_INVALID":"/errors/invalid.php",
"CSS_SELECTED":"selected"};

Props2Js is also smart enough to know that you’re assigning to an object property if you include a dot in in the --name option. In that case, it omits the var.

Props2Js is available under an MIT License and is hosted at GitHub[3].

References
  1. Maintainable JavaScript 2011 by Nicholas C. Zakas
  2. .properties by Wikipedia
  3. Props2Js
Categories: Blogs

Book review: HTML & CSS

NCZOnline - Nicholas C. Zakas - Fri, 12/16/2011 - 18:05

HTML & CSS book coverIt had been a while since I’d read a book that didn’t have to do with JavaScript or something very computer-sciency, so when I was asked to review HTML & CSS: Design and Build Websites by Jon Duckett, I was interested to see how these books have changed. I learned HTML back in 1996, and honestly haven’t picked up another book on the subject since that time.

My first impression of the book is that it’s beautiful. The text is large and the pages are colorful, making it very easy to thumb through when in a hurry. When I wasn’t in a hurry and sat down to read it, I found that the book almost told the entire story through pictures. The words are there and technically correct, but it’s the visuals in the book that really communicate information to the reader.

I admired Duckett’s approach to this book. He completely dispels with the buzzwords that glitter so many books these days. There’s mention of HTML5 and CSS3, for sure, but it’s done in such a way that it doesn’t seem gimmicky or hyped. The title of the book itself is evidence of this. Duckett clearly doesn’t want you thinking about HTML 4 vs. HTML5 or CSS 2 vs. CSS3. Instead, he wants you to understand the concepts that link together web technology and good design. Some of that is done with HTML 4 and CSS 2 while some is done with HTML5 and CSS3.

This book is really targeted at beginners without a technical background, and it does an exceptional job in serving this audience. The approach is perhaps the gentlest introduction to the concept of web programming that I’ve ever encountered. So gentle, in fact, I think that almost anyone could pick up this book and start to make a simple web page relatively quickly. It takes you right from creating your HTML file with a text editor, through learning HTML and CSS, all the way to deploying your file and adding Google Analytics.

Sprinkled throughout the book are useful tidbits about typography, contrast, design concepts, and even how multimedia plugins such as Flash work in conjunction with a web page. The very visual nature of the book makes picking up these concepts easy, as every piece of code is accompanied with a diagram, figure, or screenshot showing the result.

If you’re an experienced web developer, you’ll probably want to pass on this book since it will be far too basic. However, if you’re looking for a good book to introduce web development to an inexperienced web developer, or even someone who has no experience, then this book is a great place to start.

Categories: Blogs

Timer resolution in browsers

NCZOnline - Nicholas C. Zakas - Wed, 12/14/2011 - 17:00

Timer resolution refers to how frequently a clock is updated. For most of their history, web browsers used the default system timer for functionality such as setTimeout() and setInterval(). This meant browsers could only schedule code to run as frequently as the system timer would fire. Internet Explorer also used the system clock for seeding values in Date object, so dates could only be created with differences equivalent to the timer resolution.

A brief history

Windows machines have a timer resolution of 10-15.6ms by default (most at 15.6ms), which meant that browsers using the system timer were stuck to this resolution. Of course, 10-15.6ms is a lifetime when you have a CPU running as fast as today’s processors do. It probably doesn’t surprise you that Internet Explorer through version 8 exclusively used system timers and so led to John Resig writing about how timer resolution affects benchmarks[1]. On OS X, browser timers were much more accurate than on Windows.

Until recently, the other browsers on Window also used the system timer and so were all stuck at 15.6ms timer resolution. This was true for Firefox, Safari, and Opera. Chrome may have been the first Windows browser to switch to a higher-resolution timer[2], and their experiments led to some interesting results.

The original idea was for Chrome to have sub-millisecond timers, but this was abandoned in favor of a one millisecond timer resolution. They decided to use the Windows multimedia timer API, which allows you to specify a timer with a resolution as small a one millisecond and use that instead of the system timer. This is the same timer used by plugins such as Flash and Quicktime.

Chrome 1.0 beta had a one millisecond timer resolution. That seemed okay, but then the team started having bug reports. It turns out that timers cause the CPU to spin, and when the CPU is spinning, more power is being consumed because it can’t go into sleep (low power) mode.[3] That caused Chrome to push its timer resolution to 4ms.

The 4ms delay was codified in HTML5 as part of the Timer section[4], where it states that the minimum resolution for setTimeout() should be 4ms. The minimum resolution for setInterval() is specified as 10ms.

Timer resolution today

Internet Explorer 9, Firefox 5, Safari 5.1, and Opera 11 all feature a 4ms timer resolution, following Chrome’s lead. Prior to that, Firefox 4 and earlier and Safari 5 and earlier had a timer resolution of 10ms (apparently, this was hardcoded in WebKit). Mobile Safari on iOS 5 also has a 4ms timer resolution. Silk on the Kindle Fire has a 10ms timer resolution, potentially indicating it was built off an older version of WebKit. However, just because today’s browsers have a timer resolution of 4ms, it doesn’t mean that’s the resolution you’ll be getting.

Most browsers also do some sort of timer throttling based on different conditions. The intent is to save battery at opportune times – times when, theoretically, you either won’t notice the difference or would gladly trade for improved battery life on a laptop or mobile device. Here are some circumstances where timer resolution changes:

  • Chrome and Internet Explorer 9+ switch back to the system timer when a laptop is running on battery power. When plugged in, the browser switches back to the 4ms timer resolution.
  • Firefox 5+, Chrome 11+, and Internet Explorer 10+ change timer resolution in inactive tabs to 1000 milliseconds.[5]
  • Mobile Safari on iOS5 and Silk on the Kindle Fire freeze the timer completely when you switch to a different app. The timer restarts when you switch back to the browser.

Browsers will likely continue to make adjustments to timer resolution as it pertains to power consumption on battery-powered devices. The HTML5 spec leaves room for browser vendors to make such changes.

 

Conclusion

There has been a silent timer resolution evolution going on as browsers have developed over the past few years. Timer resolution isn’t one of those topics that gets discussed frequently, but if you’re using setTimeout() and setInterval(), it pays to have a deeper understanding of the functionality. We’re getting closer to the point of having per-millisecond control of the browser. When someone figures out how to manage timers without CPU interrupts, we’re likely to see timer resolution drop again. Until then, keep 4ms in mind, but remember that you still won’t always get that.

Update (15 Dec 2011): Updated with information about Date object.

References
  1. Accuracy of JavaScript Time by John Resig
  2. Chrome: Cranking up the clock by Mike Belshe
  3. CPU Power Utilization on Intel® Architectures by Karthik Krishnan
  4. Timers in HTML5
  5. Clamp setTimeout/setInterval to something higher than 10ms in inactive tabs
  6. Timer Resolution Test by Ryan Grove
Categories: Blogs

Vendor Prefixes Are A Rousing Success

tl;dr version: Henri Sivonen’s arguments against vendor prefixing for CSS properties focus on harm without considering value, which in turn has caused him to come to a non-sensical set of conclusions and recommendations. Progress is a process, and vendor prefixes have been critical in accelerating that process for CSS.

For a while now I’ve been hearing the meme resurface from CSS standards folks and a few implementers that “vendor prefixes have failed”. I’d assumed this was either a (bad) joke or that it was one of those things that web developers would scoff at loudly enough to turn the meme recessive. I was wrong.

Henri Sivonen, Mozilla hacker extrordinare, has made the case directly and at length. Daniel Glazman, co-chair of the CSS WG posted a point-by-point response. If you have the patience, you should read both.

Lost in the debate between “browser people” and “spec people” is the the essential nature of what has happened with prefixes: they worked. From the perspective of a web developer, any first approximation of the history of vendor prefixes are pure win, even if only a fraction of the value that has been delivered behind them is attributable to prefixes un-blocking vendors from taking risks and shipping early.

Daniel’s rebuttal to Henri gets a lot of things right, but he gives in on an essential point; by agreeing with Henri that vendor prefixes are “hurting web authors” he wites off the benefits that they’ve delivered — namely the ability of vendors to get things out to devs in a provisional way that has good fallback and future-proofing properties and the ability for devs to build with/for the future in an opt-in, degradable way.

Rounded corners, gradients, animations, flex box, etc. are all design and experience enablers that developers have been able to take advantage of while waiting for the standards dust to settle, and thanks to W3C process, it takes a LONG time to to settle. Yes, that has some costs associated with it. Henri is very worried that browsers that aren’t keeping up quickly will be “left behind” by webdevs who use only one vendor’s prefix. But surely that’s a lesser harm than not getting new features and not having the ability to iterate. And it provides incentive for following browsers to try to make a standard happen. What’s not to love? More to the point, I just don’t believe that this is a serious problem in practice. What front-ender in 2011 doesn’t test on at least two browsers? Yes, yes, i’m sure such a retrograde creature exists, but they were going to be making non-portable content regardless of prefixes. Assuming you’re testing fallback at all (e.g., by testing on more than one browser), prefixes not appearing on some browser are just the fallback case. CSS FTW! Webdevs who don’t test on more than one browser…well, they’re the ones hanging the noose around the neck of their own apps. Vendor prefixes no more enable this stupidity than the existence of the User-Agent header. Compatibility is a joint responsibility and the best each side (browser, webdev) can hope of the other is some respect and some competence. Cherry picking egregious examples and claiming “it’s hurting the web” seems, at a minimum, premature.

And how did we think we’d get a good standard, anyway? By sitting in a room in a conference center more often and thinking about it harder? Waiting on a handfull of early adopters to try something out in a tech demo and never stress it in practice? That’s not a market test (see: XHTML2), it doesn’t expose developers to the opportunities and tradeoffs that come with a new feature, and doesn’t do anything to address the inevitable need to integrate feedback at some point.

Yes, we could go with Henri’s suggestion that the first person to ship wins by default, never iterate on any designs, and avoid any/all first-mover disadvantage situations, but who among the browser vendors is perfect? And what would the predictable consequences be? I can only assume that Henri thinks that we’ll end up in a situation where vendors coordinate with the CSS WG early to add new stuff, will design things more-or-less in the open, and will only ship features to stable (no flag) when they’re sure of their design. That could happen at the limit, but I doubt it. Instead, the already fraught process of adding new features to the platform will be attempted by even fewer engineers. Who wants the responsibility for having to be perfect lest you screw the web over entirely? Fuck that noise, I’m gonna go work on a new database back-end or tune something to go faster. Browsers are made by smart people who have a choice of things to be working on, and any time you see a new platform feature, it probably came about as the result of an engineer taking a risk. Many times the engineers in a position to take those risks don’t have a great sense for what good, idiomatic web platform features might be designed, so they’ll need to tweak/iterate based on feedback. And feedback is painfully hard to extract from webdevs unless you’ve made something available in a tangible way such that they can use it and discover the limitations. Shipping things only to dev is perhaps a good idea for other aspects of the platform where we can’t count on CSS’s forgiving parsing behavior (the basis for prefixes). Syntax changes for JS and CSS seem like good examples. But for features that are primarily new CSS properties? Oy. Making the stakes even higher, reducing the ability to get feedback and iterate isn’t going to lead to a harmonious world of good, fast standards creation. It’s going to predictably reduce the amount of new awesome that shows up in the platform.

Prefixes are an enabler in allowing the necessary process of use, iteration, and consensus building to take place. Want fewer messes? There’s an easy way to achieve that: try less stuff, add fewer features, and make each one more risky to add. That’s Henri’s prescription, wether or not he knows it, and the predictable result is a lower rate of progress — advocating this sort of thing is much worse for the web and for developers than any of the harm that either Henri or Daniel perceive.

Which brings me to Henri’s undifferentiated view of harm. His post doesn’t acknowledge the good being done by prefixed implementations — I get the sense he doesn’t build apps with this stuff or it’d be obvious how valuable prefixed implementations are for work-a-day web app building — instead focusing on how various aspects of the process of prefixed competition can be negative. So what? Everything worth having costs something. Saying that things “hurt the web” or “hurt web developers” without talking in terms of relative harm is just throwing up a rhetorical smoke screen to hide behind. If you focus only on the costs but write the benefits out of the story of course the conclusion will be negative. In many cases, the costs that Henri points out are correctly aligned with getting to a better world: having to type things out many times sucks, creating demand among webdevs for there to be a single, standardized winner. Having multiple implementations in your engine sucks, creating demand from vendors to settle the question and get the standards-based solution out to users quickly. Those are good incentives, driven by prices that are low but add up over time in ways that encourage a good outcome: a single standard implemented widely.

And as Sylvain Galineau pointed out, what looks like pure cost to one party might be huge value to another. I think there’s a lot of that going on here, and we shouldn’t let it go un-contextualized. The things that Henri sees as down-sides are the predictable, relatively minor, costs inherent in a process that allows us to make progress faster and distribute the benefits quickly, all while minimizing the harm. That he’s not paying the price for not having features available to build with doesn’t mean those opportunity costs aren’t real and aren’t being borne by webdevs every day. Being able to kill table and image based hacks for rounded corners is providing HUGE value, well ahead of the spec. Same for gradients, transitions, and all the rest. Calling prefixed implementations in the wild a bad thing needs to argue that the harm is greater than all of that value. I don’t think Henri could make that case, nor has he tried.

I think the thing that most shocks me about Henri’s point of view is that he’s arguing against a process when in fact the motivating examples (transforms, gradients) have been sub-optimal in exactly the better-than-before ways we might have hoped for! Gradients, for example, saw a lot of changes and browsers had different ideas about what the syntax should be. Yes, it’s harder to get a consistent result when you’re trying to triangulate multiple competing syntaxes, but we got to use this stuff, get our hands dirty, and get most of the benefits of the feature while the dust settled. Huzzah! This is exactly> the way a functioning market figures out what’s good! Prefixes help developers understand that stuff can and will change, and they clear the way for competition of ideas without burdening the eventual feature’s users with legacy bagage tied to a single identifier.

So what about the argument that there might be content that doesn’t (quickly?) adopt the non-prefixed version, or that vendors can’t remove their prefixed implementations because content depends on it?

To the first, I say: show me a world where 90+% of users have browsers support the standard feature and I’ll show you a world in which nobody (functionally) continues to include prefixes. That process is gated in part by the WG’s ability to agree to a spec, and here I think there’s real opportunity for the CSS WG to go faster. The glacial pace of CSS WG in getting things to a final, ratified spec is in part due to amazingly drawn-out W3C process, and in part a cultural decision on the part of the WG members to go slow. My view is that they should be questioning both of these and working to change them, not blaming prefixes for whatever messes are created in the interim.

As for removing prefixes, this is about vendors just doing it, and quickly. But the definition of “quickly” matters here. My view is that vendors should be given at least as long as it took to get a standard finalized from the introduction of their prefixed version for the removal process to be complete. So if Opera adds an amazing feature behind a -o- prefix in early 2012 and the standard is finalized in 2014, the deprecation and eventual removal should be expected to take 2 years (2016). This has the nice symmetry of incentives that punish the WG for going slow (want to kill prefix impls? get the standard done) while allowing the vendors who took the biggest risks to provide the softest landings for their users. And it doesn’t require that we simply go all-in on the first person’s design to ship. Yes, there will be mounting pressure to get something done, but that’s good too!

The standards process needs to lag implementations, which means that we need spaces for implementations to lead in. CSS vendor prefixes are one of the few shining examples of this working in practice. It’s short-term thinking in the extreme to either flag the costs associated with them as either justifying their removal or even suggesting that the costs are too high.

And webdevs, always be skeptical when someone working on an implementation or a spec tells you that something is “hurting the web” when your experience tells you otherwise. The process of progress needs more ways to effectively gauge webdev interest, collect feedback, and test ideas. Not fewer or narrower channels.

Categories: Blogs

Function-ality

I’m sitting here in Derek Featherstone’s amazing a11y talk at Fronteers and I feel like I need to follow up the last post with a quick primer on the zen of function for (both of) the spec authors who read this blog.

The reason it’s offensive to the JS hacker for WebIDL to disallow new against DOM types — any of them — is that it means that it’s no longer specifying how you’d describe these types in the primitive we use over here in JS for this sort of thing: functions. This might sound nuts to folks who come from C++ or who spend their time in spec-ese, but there’s no difference between a plain-old function, a “constructor”, and a “partial” or “mixin” in JS semantics. We use functions for all of them. You can say new function(){ ... } and create an instance of an anonymous “class” in JS. You can take the same function and invoke it as a “regular function” — (function(){ ... })(); — and you can use that sort of function as a mixin or partial interface too: new function(){ (function(){ ... }).call(this); ... }. The exact same function object can even act in all of these capacities (although it’s rare). People use them as they need to, but they all boil down to functions.

What, then, does it mean for something to disallow new against some type for which you can in some otherwise get an instance in JS? The same thing when you can’t .call() it: it’s alien. It’s not a class as we know it, which means that it’s not a function, and if it’s not a function…well, it doesn’t belong. Fundamentally, it’s smuggling static semantics into a language that has perfectly good dynamic semantics for the same thing. This strikes at the very heart of what WebIDL is supposed to be for: describing JS types for things implemented somewhere else. By not allowing new and .call() WebIDL is giving JS semantics the bird, asserting that the fact that these things aren’t JS types makes them better in some way…and that is a bug, either in the perspective of the spec authors or of the specs themselves.

Luckily, the fix is easy: all WebIDL types should de-sugar to functions. All of them. All the time. No questions asked. That you will be able to use new and .call() and all the rest isn’t a bug, and it’s not something to guard against. It’s just how JavaScript rolls…and how JavaScript’s largest, most important library should roll too.

Categories: Blogs

Real Constructors & WebIDL Last Call

For those who haven’t been following the progress of WebIDL — and really, how could you not? An IDL? For the web? I’d like to subscribe to your newsletter… — the standard is now in last call, which is W3C for “alllllllllllmost done”.

Which it is not.

Before I get to why, let me first say some nice, well-earned things about WebIDL: first, it has helped us out of the ad-hoc IDL sludge that used to be how APIs for JavaScript have been exposed in the past. It has shaved off many sharp edges and is giving spec authors a single dialect in which to write their API descriptions. From a browser perspective, this is a Very Good Thing (TM). Next, the draft in question contains some wonderful changes from the status quo, particularly the addition of a sane prototype to all WebIDL-specified objects.

That all sounds good, so what’s missing?

In a word, constructors.

Well, a lot more than that, but I’d settle for constructors. Functionally speaking, it boils down to the fact that WebIDL makes spec authors do extra work to make something like this sane:

new HTMLDivElement();

Why doesn’t this work today? Funny story…see, HTML defines HTMLDivElement as a regular WebIDL interface. WebIDL doesn’t really have the notion of concrete classes, just interfaces with and without constructors. Since the HTML spec is just doing what most specs will do — adding the smallest IDL you can get away with — the JS usability of this API is left in limbo; neither clearly HTML5′s responsibility nor WebIDL’s.

So what should a contentious version of HTML5 do? One answer is to specify a constructor, turning the IDL from this:

interface HTMLDivElement : HTMLElement {};

to this:

[Constructor]
interface HTMLDivElement : HTMLElement {};

Repeat ad-infinitum for each and every interface that should be constructable in every single spec that browser vendors ever implement. Don’t miss any! And please make sure that all your spec editors are on-board with good JS APIs as a goal! As it stands today, WebIDL doesn’t even force most spec authors to consider the question “do I need a constructor here?” — spoiler: yes — let alone the obvious follow-ups like “what arguments should one take?”.

The obvious better answer here is to flip the default on interfaces, causing them to generate constructors by default unless turned off with [NoConstructor] attributes or specified as partial interfaces (i.e., mixins or traits).

Cameron McCormack who is heading up the WebIDL effort tweeted in response to my exasperation that:

I think a “W3C Web API design guidelines” document would be a perfect place for such a recommendation.

For serious? Such a document might be useful (and I’m working on something that might pass as a first draft), but what’s the argument against flipping the default here? This isn’t a dissent on the facts of the situation: most WebIDL “interfaces” that are exposed to JS are things that could be easily new‘d up to useful ends. Most specs flub this in spectacular style. Most spec authors seem entirely ignorant of the problem and the design language of WebIDL continues to lead down a primrose copy-and-paste path that has little overlap with sanity. So why punt the decision? And why did it take and act of coordination with TC39 to get the prototype thing fixed?

And Why Are We Having This Discussion Anyway?

WebIDL, for all of its virtues, is deeply confused.

If you’re reading any of the stuff in the HTML5 spec that’s describing its API this way, it’s hard to see how it would have any sane relationship to JavaScript. Sure, you could argue that there might be other languages that matter, other languages for which you’d need to be able to generate some API, but none of them rise to anything like the importance of JavaScript. It is the programming language of the web, so if WebIDL has any animating force at all, it’s JS. Then there’s the “accident of history” aspect. Early DOM was specified as a form of IDL in part because there was some expectation that other languages would need to consume it and IDL was how C++ hackers (who still make up the entire set of people working on browser engines) are/were comfortable in describing their FFIs thanks to the legacy of COM/CORBA. Hilarious examples of multi-language-ism still persist in the WebIDL spec for no apparent reason whatsoever, warping the entire design around the altar of an ideal that is either quixotic or vestigial depending on which argument you give more weight.

Since the debate was re-kindled thanks to a debate at a TC39 meeting in July, I’ve been on the receiving end of more than one webdev’s rant about DOM’s JS incoherence, generally taking the form:

Why the *#!*?^@$ isn’t DOM just #@!*@ing specified in JavaScript?

To be honest, I have no answer aside from pointing to the IDL history, the fact that browser hackers don’t tend to write JS so don’t feel the pain, and noting that WebIDL is better in some important ways. Certainly these interfaces could be specified in a subset of JS with annotations for where native behavior is required. But their larger lament has merit too: seamlessness with JS is the bar WebIDL should be judged by. I.e. does it help spec authors do the right thing by JS devs? Or does it lead them down paths that make their generated APIs stick out like sore thumbs, full of anti-social/alien behavior such that you can’t think of them as “regular” JS?

Yes, constructors are only one minor step toward reaching this aspiration, but the fact that WebIDL has gotten to last-call without a reasonable solution to them speak volumes. If WebIDL isn’t animated by the need of JS developers, it would be good if that could be loudly called out somewhere so that the community can have the spirited debate that this point demands. If it is, can we please get on discussing how best to ensure that most “interfaces” generate constructors and stop punting?

Either way, WebIDL isn’t done yet.

Update: It occurred to me, as part of the discussion in the comments, that the provision against new with a class or type of any type is completely non-sensical in JS, as is the lack of call() and apply() methods on them. Idiomatic subclassing requires that the mixin-style be available, which uses ClassName.call(this). This is what you’d do with things that are “virtual” or “partial” interfaces if you’re describing them in actual JS. And there’s no real problem with folks new-ing them up. Doesn’t happen, doesn’t matter. Strong restrictions against it are, to quote Andrew DuPont, anti-social. Long story short: there is absolutely no reason whatsoever to disable construction on any WebIDL interface. It’s deeply non-sensical from the JavaScript perspective.

Categories: Blogs

Very Simple Pusher And ColdFusion Powered Chat

Ben Nadel Ajax and JQuery Feed - Wed, 06/30/2010 - 17:39
When it comes to AJAX and WebSockets, it's hard to think about client-server interaction without eventually thinking about Chat. Chat applications are probably one of the first ways in which we ever experienced remote communication outside of the traditional web-based, request-response life cycle. As such, I think there is a certain romance with the chat paradigm - something about it just feels special in a way that I can't quite articulate. So it should come as no real surprise that I wanted ... Read More »
Categories: Blogs

Pushing Base64-Encoded Images Over HTML5 WebSockets With Pusher And ColdFusion

Ben Nadel Ajax and JQuery Feed - Tue, 06/29/2010 - 15:46
Yesterday, I started playing around with Pusher , a realtime push notification web service that allows your server to "push" updates to the client using native HTML5 or Flash-based WebSockets. If you don't know what WebSockets are (neither did I), they provide a way for the client to open up a direct line of communication with the server. The server can then send information back to the client at any time without the client having to constant ... Read More »
Categories: Blogs

Using ColdFusion With Pusher - A Notification Service Powered By HTML5 WebSockets

Ben Nadel Ajax and JQuery Feed - Mon, 06/28/2010 - 17:20
I recently signed up for the Beta program of Pusher , a realtime push notification service powered by HTML5 WebSockets. Pusher provides a RESTful web service to which you can POST client notification messages. The Pusher web service engine then relays those notifications to all clients that have subscribed to your "pusher application" over HTML5 WebSockets. From what I have read, WebSockets allow the browser to open up a direct line of commun ... Read More »
Categories: Blogs

Detecting iPhone's App Mode (Full Screen Mode) For Web Applications

Ben Nadel Ajax and JQuery Feed - Thu, 06/24/2010 - 17:11
As I have been experimenting with HTML5's new features ( SQLite , Cache Manifest , Offline Applicatio ... Read More »
Categories: Blogs