Monday, May 12th, 2008
Category: Browsers
, CSS
, Performance
Are child selectors slower than more simple brethren? This is a question that Jon Sykes sought out data for after he read the work of Jim Barraud.
His conclusion?
The skinny is that child selectors are a major performance issue.
This seemed to make sense, but to me I needed some sort of proof rather than just being told it’s that way by someone, so over the last two days I’ve tried two approaches to see if I can replicate the issue.
The first one was rather a half-assed idea that afterwards seems fundamentally flawed as a benchmark.
So I took a new approach which does seem to return some valid and rather interesting findings, particularly regarding Safari and Firefox 3 and how they react to child selectors and performance.
The tests show that there is slow down using child selectors over direct class name declarations in IE6, IE7 and Safari 3. Safari 3 being the most impacted by child selectors. Firefox 2 has some impact, and Firefox 3 doesn’t seem to be impacted at all.
That said, this is a very extreme test, it is not often you’d have 20,000 class definitions in a single page or that all of them would use 4 levels of child selector.
Thursday, May 8th, 2008
Category: Browsers
, Standards
If you ‘aint got a URL scheme, you are a nobody. That is what I thought when I saw fx:// on the first day of JavaOne.
The newest one of these that I have seen is mountpoint:// which is part of an Opera proposal for a File I/O API in the browser. You know me, extending the browser is a bit of a passion, so I was excited to see what they had come up with:
Traditionally, web applications have had little to no access to resources residing on the local filesystem. The ECMAScript interfaces for file I/O specifies a sandboxed file system, where a widget or other trusted component can gain access to the local file system.
The File I/O interfaces in this specification represent an abstract filesystem, without knowledge of the underlying filesystem’s path separators, conventions for setting file properties such as read/write permissions.
The interfaces provide methods for opening files, writing to them, creating files and directories, moving or deleting them, and so forth.
In order to work with files, an application first has to acquire a mountpoint. A mountpoint is either a reference to a file or folder on a disk, or an abstract reference to a set of files which might not necessarily be within the same folder.
If your application wants to use the File I/O API, the browser user will be asked to select a location for the virtual file system, and then you will have access to play in the sandbox.
The core interfaces are:
The FileSystem interface
In a context where the FileSystem interface is made available to applications, the interface is instantiated as opera.io.filesystem. When present, this object provides attributes and methods for acquiring access to files and folders on the local filesystem.
The File interface
The File interface represents objects in a virtual filesystem, and can represent either a file or a folder. A file object consists of a number of properties, and methods for working on these objects
File objects that are marked as persistent must persist across restarts of the application.
The FileStream interface
The FileStream interface represents a File object opened for reading and/or writing, and defines methods and attributes for doing this work.
Tuesday, May 6th, 2008
Category: Browsers
, CSS
After building a slide deck with Ben, you learn the art of a perfectionist. He would love Chris Hester’s posting on button padding that shows you how your buttons look on various browsers and operating systems. Even been frustrated when you try to style things on the Mac?
Here are a few of his findings:
- IE 6 and 7 apply extra padding to buttons with < 2px, but IE 8 doesn’t
- IE 8 and Opera add borders to all standard buttons if you zoom large enough
- Padding on the standard buttons has no effect on Mac Firefox, and Safari on both Mac and Windows
Category: IE
, Browsers
Whenever I see a post on the IE Blog that has a title like IE and XP SP 3 I hope to see “oh, and IE 6 users will be upgraded”. How much pain would be relieved when IE 6 usage is minimal?
Unfortunately, I was disappointed again:
XPSP3 will continue to ship with IE6 and contains a roll-up of the latest security updates for IE6. If you are still running Internet Explorer 6, then XPSP3 will be offered to you via Windows Update as a high priority update. You can safely install XPSP3 and will have an updated version of IE6 with all your personal preferences, such as home pages and favorites, still intact.
Friday, May 2nd, 2008
Category: JavaScript
, Browsers
, CSS
John Resig "doesn't think there's a single JavaScript developer who isn't excited about the new Selectors API specification (and the upcoming implementations)."
He was asked to provide feedback on the API, and he sent them an email with just that.
He had three concerns:
DOMElement.querySelectorAll returning incorrect elements
This is the most critical issue. As it stands DOM Element-rooted queries are borderline useless to libraries - and users. Their default behavior is unexpected and confusing. Demonstrated with an example, using Dojo:
HTML:
-
-
-
<script src="http://o.aolcdn.com/dojo/1.1.0/dojo/dojo.xd.js"></script>
-
-
var foo = document.getElementById("foo");
-
// should return nothing
-
alert( dojo.query('div span', foo).length );
-
// will return the SPAN (booo!)
-
alert( foo.querySelectorAll('div span').length );
-
</script>
-
He then asked other library authors if they agreed:
Andrew Dupont (creator of Prototype's selector engine):
My issue with this is that it violates principle of least surprise and bears no resemblance to the APIs in the wild.
Alex Russell (creator of Dojo's selector engine):
This is a spec bug.
Combinator-rooted Queries
I read about some prior discussion concerning this (especially in relation to DOMElement.querySelectorAll-style queries). This is an important part of most libraries, as it stands. Maciej's proposed solution of using :root to allow for front-leading combinators is perfectly acceptable to me (where :root is made equivalent to the element, not the document element).
JAVASCRIPT:
-
-
// jQuery
-
$("#foo").find("> span");
-
-
// DOM
-
document.getElementById("foo").querySelectorAll(":root> span")
-
This is something that a library can easily detect and inject.
Error-handling
I'm perfectly fine with the proposed try/catch solution however there must be a way of easily determining what the invalid portion of the selector was. Currently the following occurs in Safari:
JAVASCRIPT:
-
-
try {
-
document.querySelectorAll("div:foo");
-
} catch(e) {
-
alert(e); // "Error: SYNTAX_ERR: DOM Exception 12"
-
}
-
If there were extra properties to point to what the inappropriate selector was, that'd be fundamentally important. Probably the best solution (for both implementors and JavaScript library authors) would be to simply provide a character index, working something like the following:
JAVASCRIPT:
-
-
var selector = "div:foo";
-
try {
-
document.querySelectorAll(selector);
-
} catch(e) {
-
alert(selector.slice(e.position)); // ":foo"
-
}
-
It is nice to see this all in the open, and especially watching the library authors get involved in the specs that effect us all.
Wednesday, April 30th, 2008
Category: Showcase
, Browsers
, Debugging
PPK has published new event compatibility tables that test the event registration models (traditional, W3C and Microsoft) as well as event bubbling and capturing.
There is a lot of data here on the quirks of the various browsers.
Friday, April 25th, 2008
Category: JavaScript
, Showcase
, Examples
, Browsers
, Testing
, Performance

Steve Souders has released a nice little tool called Cuzillion which has the tag line of ‘cuz there are zillion pages to check, although it could also be that there are a zillion ways to do Web development!
The tool lets you test out different techniques for optimizing performance in browsers, and these tests can be saved and shared by the community.
Steve explains how the tool came about:
I’m constantly thinking of or being asked about how browsers handle different sets of resources loaded in various ways. Before I would open an editor and build some test pages. Firing up a packet sniffer I would load these pages in different browsers to diagnose what was going on. I was starting my research on advanced techniques for loading scripts without blocking and realized the number of test pages needed to cover all the permutations was in the hundreds. That was the birth of Cuzillion.
Here Steve talks about some examples:
A great example of how Cuzillion is useful is looking at the impact inline scripts have when they follow a stylesheet in Internet Explorer. Typically, a stylesheet followed by any other resource results in both resources being downloaded in parallel in Internet Explorer. (In Firefox stylesheets block parallel downloads, so this performance optimization is only applicable to IE.) Here’s a Cuzillion page that shows this: stylesheet and image downloading in parallel. Both the stylesheet and image are configured to take 2 seconds to download. Since they download in parallel the page takes about 2 seconds to load as shown by the “page load time”.
But look what happens if we put an innocent inline script between the stylesheet and image: stylesheet, inline script, and image. Now, in Internet Explorer the stylesheet and image are downloaded sequentially, which means the page load time goes from 2 seconds to 4 seconds. If the inline script is simply moved above the stylesheet the two resources are downloaded in parallel again, and the page load goes back down to 2 seconds: inline script, stylesheet, and image.
This was a great discovery. But immediately my officemate asked if inline style blocks had the same effect. No problem. With Cuzillion I just do some clicks and drag-and-drop, and can test it out: stylesheet, inline style block, image. It turns out inline style blocks don’t cause stylesheets to block downloads.
The findings from a tool like Cuzillion are really valuable. The lessons learned from poking at inline scripts and stylesheets can save hundreds of milliseconds on page load times. And it’s a common problem. eBay, MSN.com, MySpace, and Wikipedia all suffer from this problem.
Much thanks to Google for letting me release this code under Open Source. It’s not currently on Google Code but if you want to contribute let me know and I’ll do that. Try it out and send me your feedback. And share your insights with others. We all want the Internet to be faster!
Steve is talking at Web 2.0 Expo today at 1:30pm in room 2002. If you are in town, check it out and see Cuzillion in action!
Category: Browsers
, CSS
, Safari
How long have you wanted to name colors and such in your CSS instead of having to use search and replace (which breaks if you share the same colors ;) ?
We have a proposal thanks to Daniel Glazman and the ubiquitous David Hyatt.
Since the release of CSS Level 2 Recommendation ten years ago in may 1998, the Web authors' community has been requesting a way of defining variables in CSS. Variables allow to define stylesheet-wide values identified by a token and usable in all CSS declarations. If a value is often used in a stylesheet - a common example is the value of the color or background-color properties - it's then easy to update the whole stylesheet statically or dynamically modifying just one variable instead of modifying all style rules applying the property/value pair. We expect CSS Variables to receive a very positive feedback from both the Web authors' community and browser vendors.
With Dave on the author list, we can expect the following to work on WebKit sometime soon!
CSS:
-
-
@variables {
-
CorporateLogoBGColor: #fe8d12;
-
}
-
-
div.logoContainer {
-
background-color: var(CorporateLogoBGColor);
-
}
-
(via Dylan Schiemann)
Category: Browsers
, Safari

Wow, get the feeling that they are on a roll with taking Canvas / SVG like use cases, generalizing them, and making them available to people as simple CSS.
First we had CSS animations, and we are now going with CSS Masks which run across images and <video> elements:
WebKit now supports alpha masks in CSS. Masks allow you to overlay the content of a box with a pattern that can be used to knock out portions of that box in the final display. In other words, you can clip to complex shapes based off the alpha of an image.
You now have all of these to work with:
-webkit-mask (background)
-webkit-mask-attachment (background-attachment)
-webkit-mask-clip (background-clip)
-webkit-mask-origin (background-origin)
-webkit-mask-image (background-image)
-webkit-mask-repeat (background-repeat)
-webkit-mask-composite (background-composite)
-webkit-mask-box-image (border-image)
The image at the top of the post is made via:
HTML:
-
-
<img src=”kate.png” style=”-webkit-mask-box-image: url(mask.png) 75 stretch;”/>
-
And we will now see even more rounded corners:
HTML:
-
-
<img src=”kate.png” style=”-webkit-border-radius: 10px; -webkit-mask-image: -webkit-gradient(linear, left top, left bottom, from(rgba(0,0,0,1), to(rgba(0,0,0,0))”/>
-
You can even use SVG as an image input:
HTML:
-
-
<img src=”kate.png” style=”-webkit-mask-image: url(circle.svg)”/>
-
This is huge. Web 3.0 will surely be about going beyond big fonts and rounded corners, and will go towards using the same killer masks ;)
Friday, April 18th, 2008
Category: XmlHttpRequest
, IE
, Browsers
Kris Zyp gives us a glimpse at a potential future with his 100 line Ajax wrapper that tries to do the right thing cross browser for the various cross-domain models:
With IE8’s new XDomainRequest feature, a new API is added for cross-site requests, instead of using the W3C cross-site access proposal. Just for fun, I thought I would provide a little glimpse of what the classic Ajax request wrapper function may look like for the next era of web developers. Just a few simple calls to XMLHttpRequest would be way too easy, so instead we get do this:
JAVASCRIPT:
-
-
function doRequest(method,url,async,onLoad,onProgress) {
-
var xhr;
-
if ((onProgress || isXDomainUrl(url)) && window.XDomainRequest) {
-
// if it is x-domain or streaming/incremental updates are needed we will use IE's XDomainRequest for IE
-
// streaming/interactive mode is broken in IE's XHR, but for some reason works in XDR (with onprogress), so we will
-
// need to use XDR if incremental updates are necessary
-
// see bug https://connect.microsoft.com/IE/feedback/ViewFeedback.aspx?FeedbackID=334813
-
if (url.match(/^https:/) && !onProgress) {
-
// XDR doesn’t work for secure https communication
-
// see bug https://connect.microsoft.com/IE/feedback/ViewFeedback.aspx?FeedbackID=333380
-
loadUsingScriptTag(url); // script tag insertion can be more secure than XDR
-
// in some situations because it supports https
-
return;
-
}
-
xhr = new XDomainRequest;
-
// relative paths don’t work in XDomainRequest, see bug https://connect.microsoft.com/IE/feedback/ViewFeedback.aspx?FeedbackID=333275
-
if (!url.match(/^http:/)) { // test to see if it is an absolute url
-
url = absoluteUrl(location.href,url); // must have a function to turn it into an absolute url
-
}
-
if (!(method == “GET” || method == “POST”)) {
-
// XDomainRequest does not support methods besides GET and POST
-
// see bug https://connect.microsoft.com/IE/feedback/ViewFeedback.aspx?FeedbackID=334809
-
// We will try to add the method as a parameter and hope the server will understand… good luck :/
-
url += “&method=” + method;
-
method = “POST”;
-
}
-
function xdrLoad() {
-
if (xhr.contentType.match(/\/xml/)){
-
// there is no responseXML in XDomainRequest, so we have to create it manually
-
var dom = new ActiveXObject(”Microsoft.XMLDOM”);
-
dom.async = false;
-
dom.loadXML(xhr.responseText,200);
-
onLoad(dom);
-
}
-
else {
-
onLoad(xhr.responseText,200); // we will assume that the status code is 200, XDomainRequest rejects all other successful status codes
-
// see bug https://connect.microsoft.com/IE/feedback/ViewFeedback.aspx?FeedbackID=334804
-
}
-
}
-
if (async === false) {
-
// XDomainRequest does not support synchronous requests
-
// see bug https://connect.microsoft.com/IE/feedback/ViewFeedback.aspx?FeedbackID=336031
-
// so we will try to block execution on our own (which is not really possible in any reasonable manner)
-
var loaded;
-
xhr.onload = function() {
-
loaded = true;
-
xdrLoad();
-
}
-
xhr.open(method,url);
-
xhr.send(null);
-
while(!loaded) { // try to block until the response is received
-
// I am sure the user won’t mind just clicking OK so we can block execution
-
alert(”Waiting for the response, please click OK because it probably is here now”);
-
}
-
return;
-
}
-
else { // do an asynchronous request with XDomainRequest
-
xhr.onload = xdrLoad;
-
xhr.open(method,url);
-
xhr.onprogress = onProgress;
-
}
-
}
-
// we will mercifully skip all the branches for ActiveXObject(”Microsoft.XMLHTTP”) to accomodate IE6 and lower
-
else {
-
xhr = new XMLHttpRequest; // use the standard XHR for same origin and browsers that implement cross-site
-
// W3C requests and streaming
-
xhr.open(method,url,async);
-
xhr.onreadystatechange = function() {
-
if (xhr.readyState == 3) // interactive mode
-
onProgress(xhr.responseText);
-
if (xhr.readyState == 4) // finished
-
onLoad(xhr.responseText,xhr.status);
-
}
-
}
-
xhr.send(null); // finally send the request whether it be XDR or XHR
-
-
// and supporting functions
-
function absoluteUrl : func