Blog
August 13th, 2008
For the upcoming Firefox 3.1 release a lot of work has been going into improving its CSS support (specifically, in relation to the CSS 3 specification).
One areas that have received solid implementations is that of border-image. This is a new CSS 3 module that makes the exact slicing of images (and their positioning around an element) quite easy.
The most obvious use case for them exists in constructing beautiful scalable buttons. And there is, perhaps, no better use case than the one provided by the iui library: replicating portions of the iPhone user interface in a pure-CSS manner.
Here are two examples from the iui library (slightly tweaked to support both WebKit's and Mozilla's implementations of border-image).
You will need a nightly release of Firefox in order to have the following demos work properly.
The button on the top right ("Search") is mostly implemented using the following CSS:
border-width: 0 5 0 5;
-webkit-border-image: url(toolButton.png) 0 5 0 5 stretch stretch;
-moz-border-image: url(toolButton.png) 0 5 0 5 stretch stretch;
With toolButton.png looking like:

The premise behind border-image is complex, but easy to learn. When used in the manner shown above you are, effectively, providing slice offsets into the provided image - telling the browser how to position the slices.
For example the 5s in the border-width and border-image indicate that there should be a 5px-wide border on the left and right of the button. The contents of the border should be populated with the left and right-most 5 pixels from toolButton.png. Since a horizontal border width value is provided it is possible to scale the contents of the button horizontally (inserting more contents will allow it to continue to work properly).
The 0s, on the other hand, indicate that entirety of the button background should be consumed by toolButton.png - and that none of it should be used to show the border (border-image can be used as a crude mechanism for injecting background images). Because of this the image won't be able to gracefully scale vertically.
CSS3.info provides another example that shows how the stretching and rounding work.
with the following base image:

Rounding:

Stretching:

By tweaking the stretching of the border-image you can end up with some truly-compelling results.
We can see another one in a second iui button:

With the following CSS being used:
-webkit-border-image: url(whiteButton.png) 0 12 0 12 stretch stretch;
-moz-border-image: url(whiteButton.png) 0 12 0 12 stretch stretch;
together with this base image:

border-image has a large number of compelling use cases. It's fantastic to see some coordinated efforts by browser vendors to make their implementations common-place.
Tags: mozilla, css3, css, firefox
19 Comments on 'border-image in Firefox'
July 10th, 2008
This week I've been busy working on implementing a test suite for the Selectors API specification. I picked up a new microphone recently so I decided to do a quick walkthrough of the work that I've been doing and how I've been going about it. You can view the the video below:

Implementing a Selectors API Test Suite
You can run the test suite for yourself here (it's still very much in flux - there are various parts that may still be wrong):
http://ejohn.org/apps/selectortest/
Here's a quick break down of a test run that was done earlier:
- Special Firefox 3.1 Build (73.8% - More details)
- Safari 3.1 (49.3% - No Fragment or Namespace support)
- WebKit Nightly (51% - No Fragment or Namespace support)
- Opera Gogi - "ACID3 Build" (76.7% - No Fragment support)
- IE 8 (Can't run - the file is proper XHTML so it tries to download it.)
- Firefox 3, Opera 9.5, IE 7 (0%)
The work that is being done to implement the specification in Firefox can be seen on its associated Bugzilla bug. I'm shooting very hard to make sure that everything is in place so that this makes it in to the upcoming Firefox 3.1 release (the first alpha of which is due out in a couple weeks). The benefits that this will have for both JavaScript libraries and their users will be tremendous.
Tags: w3c, mozilla, firefox, css
18 Comments on 'Implementing a Selectors API Test Suite'
July 1st, 2008
Like every web developer I've spent a lot of time using the Firebug extension to Firefox in my day-to-day development. I've found it interesting to see how my development methodologies have changed with access to that tool.
Unsurprisingly, my personal development style mirrors much of the general web dev public. But what I find most interesting is to try and track trends in web development that Firebug has single-handedly revolutionized.
Firebug Advances
Performance Profiling
Prior to Firebug there was only rudimentary analysis of JavaScript performance (using tricks like injecting timers and computing the difference). Firebug brought us the ability to analyze all function calls during a period of execution, see how they each affected each other and, probably most important, see the difference in the sub-millisecond range.
Previously none of these techniques were possible with pure-JavaScript techniques - having the ability to tap into the JavaScript engine (which Firebug does) is fundamentally important to getting good analysis.
You can see an immediate interest, by JavaScript library authors, in the performance of their code bases around the time of Firebug's introduction of profiling.
Console logging with object introspection
Logging statements has always been possible with JavaScript (and, most infamously, with the alert() function) however Firebug gave us something significant: The ability to click and introspect into logged objects. This includes the ability to click DOM nodes (and see their properties and methods) and even normal objects (like Arrays or Object literals).
Firebug has to maintain a lot references to point to where these objects exist - and it wouldn't be possible in pure-JavaScript without introducing an excessive number of memory leaks.
Current Styles / CSS Rules
There had existed some tools for examining the current CSS style values of a DOM element (such as its dimensions and positioning) but Firebug brought a whole new level of inspection: The ability to see which stylesheet rules were introducing specific styling on an element. Not to mention the ability to edit the rules in-line (along with disabling them outright).
This level of inspection completely overhauled Web Design - and has been able to detach many web designers from their IDE-of-choice into a more agnostic view of CSS design. Absolutely the biggest short-coming of this feature is its inability to work cross-browser (although, that argument can certainly be used for most Firebug features).
Network Performance
Firebug's network tab gave developers the ability to see - in very real terms - two things: 1) How long a resource was taking to load and 2) How the loading of that resource was blocking the loading of other resources. #2 is especially important, seeing that the execution of JavaScript blocks other actions from occurring can be an eye-opening experience to most developers. Or even seeing how a slow-loading stat tracking script can prevent the further display of the page.
XMLHttpRequest Inspection
While XMLHttpRequest use existed prior to the existence of Firebug it was horribly hard to debug - it was rarely obvious where errors were occurring - on the client-side? on the server-side? in the transmission? The ability to see how the requests occurred - and very importantly - how long they took (and even how frequently they occurred!) has done much to improve the overall quality of Ajax use on web pages.
JavaScript Debugging
I would've said that JavaScript Debugging was a piece of that equation, as well, however Venkman definitely lead the way, in that respect (and has been a de-facto debugger for quite some time).
I'd argue that these trends wouldn't be where they are right now if it weren't for Firebug - and that tools are the primary reason for a development strategy's success. As a corollary look at the relative success of web standards - I'd argue that adherence to HTML or CSS wouldn't be where it is today without the tools to verify a page's compliance.
How to Improve
The question now becomes: What are the next set of tools that Firebug can introduce that will revolutionize its respective areas of development?
I'd like to propose a couple, possible, areas of interest:
JavaScript Library Analysis
As it stands Firebug's JavaScript function analysis is, perhaps, too finely-grained to provide help in many instances - especially when the use of JavaScript libraries is at play. For example, when using jQuery, you're generally more concerned with finding out how fast, or slow, a particular method is - or a selector - not the performance of all the individual internal methods of jQuery.
I began some of this analysis with my Deep Profiling jQuery Apps experiment but that's really only a test. Smart integration of JavaScript library knowledge into Firebug can provide significant details about how your code should be performing.
Visual Performance Profiling
Application performance profiling is rather clumsy right now, we have a number of disparate resources (network performance, rendering performance, script performance) that we need to mentally merge to create a full picture of what's happening. To counter this I'd like to propose a way of visually viewing how components of a site affect its overall performance. Perhaps a way to break things down like this:
- Header: 300ms: 20ms Transmission + 20ms Parsing + 60ms CSS + 200ms JavaScript
- Google Ad: [BLOCKING RENDERING] 600ms: 20ms Transmission + 20ms Parsing + 20ms CSS + 240ms JavaScript + 300ms Frame Loading
- Sidebar: 400ms: 40ms Transmission + 40ms Parsing + 80ms CSS + 240ms JavaScript
The YSlow Firebug plugin already provides some level of analysis on your site - but it's much more holistic (giving you generic tips for files and pieces of code). Whereas a more specific approach would be greatly appreciated.
Ajax Improvements
We currently have the ability to view XMLHttpRequests as they occur, which is great, but some additions could be made that would serve to be quite helpful, such as:
- The ability to manipulate a request and re-submit it. If you're attempting to see how different inputs will affect your site, this would be a great way to play back requests or see how they can be best improved.
- Right now Firebug only lets you know the basic textual output that's coming from the server-side. Having it be able to tell you if incoming XML, JSON, or even HTML is syntactically correct (and even being able to navigate the resulting structures - as the browser would see them) would be a huge boon. As it stands it can be quite frustrating to receive a slightly-malformed response from a server and be stuck trying to figure out what's going wrong.
- Better JSON/JSONP integration is essential. There are a large number of Ajax requests being done through dynamic script tag injection - and those are completely unmonitored by Firebug's XMLHttpRequest tracking. Being able to see what requests and responses look like - and where errors may be occurring - would be immensely useful.
Rendering Performance Analysis
While we have fantastic tools for digging in to the performance of JavaScript - CSS is a complete unknown. How much overhead do our stylesheets provide? How many elements does this CSS rule affect? Does this rule cause a costly reflow to occur? and how many times? How long does it take to render a particular portion of a page? Would changing the structure of my page help to improved perceived rendering speed?
Virtually all of these questions are un-answered and we need a tool to help provide a solid response.
Security Analysis
Security is one area that has seen virtually no attention in the respect of user tools. Most developers have no idea how secure their web site is or how vulnerable it may be to attacks. There needs to be easily-accessible tools for testing:
- SQL Injection attacks
- XSS Injection
- Susceptibility to Spoofing (Data Encryption)
At the very least. The problem here is that while these tools will be incredibly useful for developers to improve their web sites - it'll also encourage malicious behavior. Although, arguably, those that wish to be malicious already have the tools to do so.
Standards Integration
Inline support for analyzing the standards-compliance of a page. Being able to see notes next to specific elements, attributes, CSS rules, etc. that show information on how they don't comply with particular standards - or even how they could be improved to match standards.
This includes inline strictness warnings for JavaScript (produced by the JavaScript engine).
I think that compliance should go a step further, as well, and look to provide information on Microformat and RDFa compliance - pointing out specific errors and helping sites to become better formatted.
Finally - RSS and Atom standards compliance. Notifying a developer that their site's RSS/Atom feed is malformed would allow them to immediately make a more compliant feed (a common area of mistakes).
Internet Explorer Support
The final, and perhaps most difficult, item that should occur would be a port of Firebug over to Internet Explorer. Both Safari and Opera have web developer tools integrated into their browsers - however Internet Explorer still consumes a majority market share and there's no good tools in sight. (I, personally, use CompanionJS but it's still a far cry from the full suite of utilities that Firebug provides - especially in the realm of DOM/CSS.)
This could probably be remedied if there was a really good pure-JavaScript Firebug (although the overhead associated with many of Firebug's features would lead to an astronomically-sized implementation). The current "Firebug Lite" is something of a joke - only vaguely functioning in modern browsers.
Not only do I want to see Firebug improve - it's imperative that Firebug continue to improve, for the sake of web developers everywhere. If it simply stalls and works into a stasis of bug fixes then web developers will be stuck with the current set of tools for quite some time. While other browsers are improving at a rapid pace, it'll still be quite some time before they are able to match the current feature-set of Firebug.
Since so much of web development ecosystem is currently linked to the health of a single tool advances have to be made now and they have to be made quickly in order for the web to flourish and survive as a development medium.
Tags: development, firefox, firebug, javascript, css, programming
42 Comments on 'Powering a Web Revolution'
June 25th, 2008
Visit: New CSS Features in Firefox 3
David Baron, a Mozilla developer, has a write-up on the new CSS features that are available in Firefox 3. There's a mix of additions - everything from CSS 2.0 and 2.1 features to new additions that are tracking CSS 3.
Some of my favorite additions include:
The CSS 3 Box Specification (in the form of -moz-max-content, -moz-min-content, -moz-fit-content, and -moz-available values to width, min-width, and max-width).
-moz-fit-content actually does let authors do some things that previously weren't possible without tables, such as putting a background on headings that doesn't fill the whole width of the container unless the heading does, but is a single rectangle if the heading breaks to multiple lines (see Demo).
Wrapped whitespace (white-space: pre-wrap). This allows you to have a <pre/> whose contents are wrapped nicely, while still maintaining its rigid structure.
rgba() values. You can now apply opacity directly to background colors (as opposed to having to create a shim div/span and styling that instead). Note that the below text is fully opaque.
body { background: url(stripes-6); }
div { background: rgba(0, 255, 0, 0.5); }
h2 { background: rgba(255, 0, 0, 0.5); }

inline-block and inline-table Such a powerful addition - and one that now brings Firefox in line with most other browsers. It'll allow you to create much-more-complicated layouts that were previously very trying to implement using normal CSS. Demo.
Tags: firefox, mozilla, css, links
11 Comments on 'New CSS in Firefox 3'
May 15th, 2008
There's been a lot of interest in yesterday's release of Google Doctype. The primary focus of the release is on documentation (specifically "documenting the Open Web") however there's also two extra, hidden, additions: A Google-released JavaScript library and an Open Web test suite. Let's break down the parts of this release.
Documentation
On the main Google Doctype site they provide a link to Browse Google Doctype which takes you to a JavaScript-laden site through which you can read the various articles that they provide. If, instead, you'd prefer to read something a little more static (and sanely linkable, bookmarkable) you can just go straight for the Google Doctype Wiki instead.
The documentation falls into 2 realms:
DOM and CSS
These are sort of API references to all the DOM and CSS properties. However, browsing through, they don't seem to be terribly useful. At best, these references are programmatically generated (seeded with initial values). It's not completely clear what its setting out to achieve but my guess is something like "if we put all the information in a wiki, maybe people will come and fill it out," which seems a little awkward (especially since it's already been done before).
The primary original content provided by this reference is related to the 'browser compatibility' section of each item. For example, examine the background-postition CSS property page. There's a whole bunch of information being tested for - and a whole lot of 'N's in the columns - in fact there's even a couple rows that contain nothing but 'N's. This says to me a couple things:
- When every browser fails a test then you're probably testing the wrong thing.
- The fact that the actual return values aren't shown makes this extra frustrating (every browser fails background-position: left - but what do they fail with? what are they returning, instead?).
- There doesn't seem to be any attempt to test for compliance. Overwhelmingly the test values appear to be "the value that goes in should be the value that comes out" - which is rarely the case. Granted, it's much easier to write tests of this nature (just generate them programmatically) but the end result doesn't really help anyone.
How-To Guides
The final portion of the documentation centers around a number of articles relating to JavaScript/DOM programming.
A number of these articles are quite good (such as the Web Security section and a couple of the other articles). However, the rest of the articles are quite... confusing. They appear to be documentation for methods of a Google JavaScript library, however they're presented as Copy-and-Paste examples that developers can use. I think most developers will be quite disappointed when they find out that it's not possible.
On the article pages the Google JavaScript library is never mentioned, nor linked to. You can eventually find it if you go to source, browse the SVN (to the right directory), and download the individual files of the library.
I think I can safely say that this is the first time that documentation for a JavaScript library has been released before the library itself.
Google JavaScript Library
The second portion of the Google Doctype release was the public unveiling of the (for lack of a better name) "Google JavaScript Library." It, currently, only existing in Google SVN. There doesn't appear to be an API reference, either - beyond the various articles provided in the above How-Tos.
Digging through the code there appears to be a huge depth of coverage for some... rather obscure JavaScript topics. If anything has been shown during the last couple years of JavaScript library development (in that the functionality that users have been asking for, and using) is that DOM traversing, DOM manipulation, Events, Ajax, and Animations are fundamental. While the Google JavaScript library does provide some DOM manipulation and Events they completely ignore all other aspects of JavaScript development. Instead they delve off into the land of object traversal, string manipulation, math helpers, and data structures.
If I had to pick a library that this one was closest to I'd have to say MochiKit. I wasn't very surprised then to find out that the Google JavaScript library's DOM helpers were heavily inspired by MochiKit.
No offense to MochiKit or the Google JavaScript library but if past history is any indicator - developers are not clamoring for another MochiKit.
Open Web Tests
The final portion of this release is related to the programmatically-generated Open Web API reference. This is a full suite of tests that cover HTML elements, JavaScript/DOM methods, and CSS properties.
Thankfully raw dumps of the results are provided for each browser so we can use this as an opportunity to see what tests are being performed (and how the results compare).
Taking a look at the JavaScript/DOM results for Firefox 3 we see a lot of 'existence' tests. The vast majority of the tests appear to be checking to see if particular methods, or properties, exist. Scroll through we see some puzzling error messages:
3. document/document-attachEvent-typeof-test.html:testTypeOf failed
"[DocumentAttacheventMethod] typeOf(document.attachEvent) != 'undefined'"
Expected not to be <undefined> (String)
Firefox 3 is failing this test because it doesn't have Internet Explorer's proprietary attachEvent method? If you continue through the results you'll see similar indicators all throughout. If you were to open Internet Explorer's results you would see a number of fails for Netscape-specific methods/properties.
Opening up the HTML Firefox 3 results we see a similar situation. In this case the HTML tests appear to focus on the availability of attribute expandos on DOM elements. For example, here's one failing test from Firefox 3:
293. attributes/ilayer-above-reflection-test.html:testReflection failed
"[IlayerAboveAttribute] ilayer.above reflects <ilayer above="foo">"
Expected <foo> (String) but was <undefined>
The ilayer element was a Netscape-specific HTML extension. Testing for its DOM compliance (and, by extension, its existence) seems quite futile.
If I had to guess as to how these tests were generated I'd say "open up a browser, spider every DOM property (or HTML attribute), and turn those into existence tests."
This raises an important point: This suite is not built for any sort of standards compliance - at all - it's simply designed to check for compatibility between browsers. Looking at this suite as a compatibility suite we can start to see some use - but it's still terribly limited (only checking for existence is hardly a good-enough indicator of a browser's proper support of a property or method).
If there's one over-arching theme to the Google Doctype release it's been "whatever we can generate automatically, or release with the least amount of fuss, let's do that, no matter how simple it may be." I'm definitely looking forward to when a full release comes along, but this doesn't appear to be it.
Tags: html, css, google, documentation, javascript, library
35 Comments on 'Google Doctype'
March 15th, 2008
A common - and desirable - technique for constructing JavaScript-based web applications is that of progressive enhancement: only providing capable browsers with the features that they are capable of utilizing - but providing incapable browsers with an adequate, albeit degraded, experience otherwise.
This provides the best of both worlds: Users of modern browsers (the majority audience) can get the best experience while those that are using incapable browsers (such as most mobile devices) will still get an interface that suits them well.
There's one thing, overriding in all of this, however: Progressive enhancement is nearly only ever applied to the JavaScript functionality of web applications. Presumably it's assumed that if a browser is capable of supporting the desired JavaScript features of an application then it must, also, be capable of supporting the specific CSS styling as well.
One technique that has greatly interested me, as of late, is one employed by the Filament Group (a local design shop here in Boston): Progressive CSS Enhancement. The premise is that progressive enhancement is done with page styling in mind, primarily, rather than from a purely-JavaScript perspective.
This is particularly important for a couple reasons:
- It should be easy to degrade page styling in a manner that isn't reliant upon CSS browser hacks - this technique makes it so.
- Not all pages utilize heavy JavaScript (and, thus, progressive JavaScript enhancement does not apply to them).
Their technique works as follows: You choose to provide the user with, either, the enhanced or the decreased experience by default. In either case a basic script is run which attempts to verify a couple CSS styling behaviors along with some basic JavaScript functionality (just enough to be able to run the test).
A couple of the CSS techniques that they test for:
- Box model: make sure the width and padding of a div add up properly using offsetWidth.
- Positioning: position a div and check its positioning using offsetTop and offsetLeft.
- Float: float 2 divs next to each other and evaluate their offsetTop values for equality.
- Clear: test to make sure a list item will clear beneath a preceding floated list item.
- Overflow: wrap a tall div with a shorter div with overflow set to 'auto', and test its offsetHeight.
With those in place you can pretty safely begin designing a useful CSS-based layout. Note that the experience will only ever be upgraded if all of the tests pass - if any fail then it simply won't continue. Obviously there'll still exist some browser discrepancies (like in the differences in the box model between Internet Explorer 6 and most other browsers) but that's usually an acceptable level of hackage (meaning that you won't have to deviate much from what you're already doing).
The actual implementation is quite simple. It consists of a number of JavaScript-based rules that test for behavior. For example the following rule tests for a working box model:
var newDiv = document.createElement('div');
document.body.appendChild(newDiv);
newDiv.style.visibility = 'hidden';
newDiv.style.width = '20px';
newDiv.style.padding = '10px';
var divWidth = newDiv.offsetWidth;
if(divWidth != 40) {document.body.removeChild(newDiv); return false;}
That check, alone, is able to knock off a number of older browser whom aren't able to successfully implement that CSS behavior. Currently all the rules are in a large code block, which makes maintenance unwieldily. I think that this library could definitely benefit from extensibility (being able to add/remove rules that you wish to honor).
When it comes time to actually use this technique within your application there are a number of strategies that you can use. However, for the sake of discussion here, let's assume that you're sending, by default, the degraded experience to the client (optionally upgrading if the browser is capable). Then you would be able to use these two techniques:
- A class of "enhanced" is assigned to the body element to be used for optional CSS scoping (such as:
body.enhanced {background: red;}).
- Any links to alternate stylesheets that have a class of "enhanced" will be enabled.
In this manner you can specify all of your stylesheets in your header with some disabled (being alternate stylesheets) or with some CSS rules being only applied with the body.enhanced match.
Their implementation also allows you to only execute JavaScript if all the rules pass - however I'm not sure if that's an acceptable solution, in this situation. If you want to verify that your desired JavaScript functionality is able to operate then you should check for just that. However, in this case, we can get the other side of the equation: Verifying that CSS works as you would expect it to, knowing that an adequate experience can be provided.
If you're curious as to which devices are supported by the default rules in the test file you can view the result matrix on the tool's site.
I definitely think that this technique has a lot of merit, especially in the realm of mobile-accessible web sites. Since it's virtually impossible to design, and test, your pages to work on such a large number of obscure platforms this degraded strategy is really one that will help to benefit both you, and your users, in the long run.
Tags: design, javascript, css
21 Comments on 'Progressive CSS Enhancement'
February 20th, 2008
When doing DOM-based performance testing you frequently need to pick a sample HTML document to work against. This raises the question: What is a good, representative, HTML document?
For many people a good document seems to file into one of two categories:
- A large web page with a lot of content. When we did our initial performance testing with jQuery we used Shakespeare's As You Like It (lots of elements, but a very flat structure) - Mootools uses an old draft of the W3C CSS3 Selectors recommendation. This has a lot of content, as well - thousands of elements with a medium depth structure.
- A popular web page. Common recommendations include 'yahoo.com' and 'microsoft.com'.
What's troubling is that there doesn't really seem to be any way to determine what a representative web page actually is. There's a couple things that I'd like to propose as being good indicators:
- Standards-based semantic markup (including strong use of attributes: id, class, etc.).
- Non-trivial file size and element count (testing the scalability of the performance).
- Some use of tables and form elements (frequent inclusions in most web pages).
- Strong use of CSS (frequently implies a deep element structure, in order to accommodate complex layouts).
- Pervasive use of JavaScript. If JavaScript performance analysis is being done it's probably good to start with a page that already has a desire to use it.
I think, out of all of these aspects, one page stands out: CNN.com. Here's why:
- It uses semantic HTML 4 markup with a lot of classnames and ids.
- It's about 92kb in size and has 1648 elements in it.
- It has some tables (seemingly for legacy material) and some forms (search forms, drop-downs).
- Lots of CSS and JavaScript. Makes good use of Prototype which, at least, should show an desire in having a page with performant JavaScript.
- It's, also, imperfect. I would consider this to be desirable. Rarely are pages completely without fault - and the heavy use of embedded JavaScript, ads, and non-semantic tables helps to add a stark dash of reality.
Of course, analysis could always be done against multiple pages and be viewed in aggregate but we need a place to start. So, what do you think; is CNN a good, representative, page for doing performance analysis against?
Tags: javascript, css, html, performance
12 Comments on 'A Typical HTML Page'
February 12th, 2008
This post has been a long time coming. It's a combination of my distrust for JavaScript CSS selector performance analysis and my disdain for the CSS 3 Selector specification.
To start, I want to give a little bit of history regarding jQuery's selector engine. When I first started working on its implementation it was mid-2005. It was mostly done as a personal challenge to myself - implementing a specification for kicks. You can see some of my early thoughts in a post that I wrote on Selectors in JavaScript. I completed my implementation on the same day as the first, other, JavaScript CSS selector engine: cssQuery. I then held of and merged it with some of my other efforts, which eventually resulted in jQuery. When I first implemented the engine, I went for full CSS 3 compliance (mashing in XPath-capable queries, as well).
Fast-forward 7 months and jQuery is starting to get a capable community. In preparation for jQuery 1.0 I decide to analyze the features of the engine to see what people are actually using. I ran a poll (which, unfortunately, has been lost) in which I asked the users which selectors they used. As it turned out there were a great number that no-one had any use for, whatsoever (and, in fact, this remains true to this day). At this point I removed them from the engine, breaking compliance with the CSS 3 Selector spec. Here's some of the selectors that were removed:
- E:root - Rarely used in HTML. You already know what the root node is - it's named 'html'.
- E:empty - This might be useful if it could include empty whitespace text nodes, but it doesn't. This will only match elements like <img/> and <hr/>, for whatever use that is.
- E:lang(fr) - This could be achieved in so many other ways - but in the end, how many multi-language-on-the-same-page sites are there?
- E:nth-of-type(n) - I'm not sure what the motivation was for creating all the -of-type methods, I'm sure it sounded great on paper, but in the world of HTML it's not very useful.
- E:nth-last-child(n) - Another "great on paper" method. Don't think I've ever seen it used.
- E:nth-last-of-type(n)
- E:first-of-type
- E:last-of-type
- E:only-of-type
- E:only-child - When does this occur? and why would you need to select it?
- E ~ F - Only selects adjacent elements, in one direction. Why a ~? Why only one direction?
- E + F - Only the next element - rarely useful.
- E[foo~="bar"] - Only matches values in a space-separated list. This is only useful for classes (which is taken care of with .class) and the ref attribute. Why not just use *=?
- E[hreflang|="en"] - Another selector that is really only useful for a single attribute - and not a popular one, at that.
What's fascinating is that no one has ever, ever, requested that these features be added back in. They have virtually zero real-world use and applicability. In fact, with the exception of "E + F" all of these selectors were added, exclusively, in the CSS 3 specification. I'm not completely sure what the thought process was in selecting them, but it's pretty obvious that it wasn't grounded in application, but in theory (which isn't really the spec-writers fault, considering that there were very few CSS 2-compatible implementations at the time).
Only later, after performance test suites started to arrive, did people start to care about the existence of - and the performance of - these selectors (and hence why selectors like +, ~, and [foo~=bar] now exist in jQuery).
To compensate for the shoddy offering of current CSS selectors, JavaScript libraries have had to write whole supersets of selector functionality to compensate for missing features. For example, jQuery includes both new selectors (such as ":hidden" and ":has()") and new selector methods (like ".parent()" and ".prev()") - all of which provide the user which phenomenally more functionality and clarity than the what is in CSS 3.
Now, I'm sure I'll probably get lots of feedback saying "but 'E + F' can be useful, look at this example" or "of course ~= is useful, you can use it on rel attributes" - that's not the point. The fact is that they are woefully un-used. To the point that they are a burden upon the implementors of the specification. What's the point of implementing the above features - or more importantly: optimizing the above features for speed - if no one is using them.
Which leads me to my next bone to pick:
Performance isn't Compliance
Everyone and their brother seems to use the SlickSpeed selector speed test suite. That's fine, as far as implementation goes it's a pretty good take on the matter. It runs quickly, spits out pretty results - users love it. However, it's doing two things - and that's one thing too many: It's testing for both performance AND compliance of the selector engines. For example, if a user were to run the tests and see poor performance for, oh say, :nth-child(2n+1), they would be shocked, nay, appalled at the overall performance of that selector engine. But here's the rub: That's from a selector that is virtually un-used. (:nth-child is occasionally useful, in and of itself, but the An+B syntax is virtually worthless). But this is a point on which SlickSpeed does not care - since it's also testing for compliance, in addition to performance, all tests are treated equally and "without bias."
However, that's precisely what isn't needed: Selectors require bias. I've often argued that the speed of an ID selector is far more important than the speed of an attribute selector (for example) because of how commonly it's used. However, up until this point I've never had data to back up this claim. I have resolved that.
I present to you the most commonly used CSS selectors used by jQuery from 59 of the most popular jQuery-using sites (which was borrowed from the featured sites list). (Fun fact: The use of $(DOMElement) was more popular than all other selectors combined.) Here's a small selection of the selectors found:
| Selector |
% Used |
# of Uses |
| #id |
51.290% |
1431 |
| .class |
13.082% |
365 |
| tag |
6.416% |
179 |
| tag.class |
3.978% |
111 |
| #id tag |
2.151% |
60 |
| tag#id |
1.935% |
54 |
| #id:visible |
1.577% |
44 |
| #id .class |
1.434% |
40 |
| .class .class |
1.183% |
33 |
| * |
0.968% |
27 |
| #id tag.class |
0.932% |
26 |
| #id:hidden |
0.789% |
22 |
| tag[name=value] |
0.645% |
18 |
| .class tag |
0.573% |
16 |
| [name=value] |
0.538% |
15 |
| tag tag |
0.502% |
14 |
| #id #id |
0.430% |
12 |
| #id tag tag |
0.358% |
10 |
View the rest of the selectors with a full explanation...
I spidered the JavaScript of all the sites, parsed through them, and found the appropriate selectors to compile the list. Here's some things that I learned from the data:
There doesn't seem to be a correlation between performance and selector use. For example, ".class" is far more popular than "tag.class" even though the second one is much more performant. What's especially important about this is that the degree of performance hit isn't that much of an issue. For example, the difference between 4ms and 30ms is virtually imperceptible. Instead there is an overwhelming trend towards simpler selectors. Obviously, user education could help, but it's unclear as to how much that will change things in the end.
A couple of jQuery's custom selectors are immensely popular: :visible, :hidden, and :selected. However it is unclear as to how useful they would be outside of a JavaScript-based CSS selector engine (there's no real point in styling a hidden element).
A bunch of jQuery's convenience selectors: :checkbox, :radio, :input, etc. would be quite useful, within a CSS selector spec - and it's good to see them in wide use here.
There's a bunch of unexpected queries that are used: "*", ".class .class", "[name=value]", and "#id #id". These types of queries are grossly under-represented in current performance test suites.
...there's one thing that needs to be taken from all of this data, though: Speed test suites need to test reality rather than specification.
I'm perfectly ok with having two completely separate suites, one focusing on speed and one focusing on compliance, however mixing them does no one any favors: Users get a confused perception and suite authors (and browser vendors!) waste time dealing with optimizing things that don't matter.
My proposal: A standardized performance suite (based on SlickSpeed, is fine) but populating the tests with comparable selectors to the ones shown above and weighted based upon their relevance. Thus, the speed of the #id selector should, actually, consume 51.29% of the total final score. This means that being 3x faster at this test would actually be 102x more important than becoming 3x faster at "tag tag". This is absolutely not represented in any, current, test suites and needs to be rectified. Of course, I'll be happy to seed my selector list with results from other popular sites of other selector libraries.
I'll be fine constructing this suite, as well - I just want to make sure that there's enough interest. I think this proposal has a lot of merit and should be strongly considered - the result will be a selector performance suite which will benefit everyone.
Tags: jquery, javascript, performance, css
70 Comments on 'Selectors that People Actually Use'
·
« Previous entries