Follow-up: Don’t use class names to find HTML elements with JS

This is the follow-up to “Don’t use class names to find HTML elements with JS“, where we take a look at a new test case, with results proving that the negative speed impact of finding elements by data attribute instead of by class name is negligible. The reasons for using this approach are in the original post and still current. If you just don’t like the concept, there’s no way I can persuade you. But if it’s about the numbers, here are the metrics.

TL;DR;

Targeting elements by data attribute using jQuery is almost as fast as doing so by class name. Except in IE, but even with the slower speeds it seems to be fast enough for real world situations (IE9 takes 9 milliseconds to find 376 elements in a DOM of 1,364; Chrome takes 1 millisecond).

Creating a real world test

Back in January I wrote about how I think you shouldn’t use class names to target elements from your JavaScript (and as an addition, I don’t think you should use ID’s in your CSS either). My blog spiked from 15 to 3500 readers a day (for a single day…) and I received a ton of responses, both online and offline. Offline, people seemed to think it was a pretty cool approach, saying that they were definitely going to give it a try. Online the majority was telling me I was doing it wrong (not to my surprise). They said the concept is flawed, my test case didn’t represent a real world example and in practice it’s too slow to be usable in any web app.

For a while I ignored those who didn’t agree, mostly because a lot of them used arguments I couldn’t compete with (“no Sir, my parents had me tested” would have been the best response to many). The thing kept nagging though. Was I wrong? Was the test case I used indeed insufficient (I didn’t write it myself)? Would that have a massive impact on the numbers? There’s only one way to find out, so I created a life-like test case at jsPerf. Dozens of people ran the tests on a multitude of different devices, with yours truly testing on iPads, iPhones, Android phones & tablets, Windows Phone and BlackBerry. Plus my desktop browsers and a bunch of browsers running on Windows in Parallels.

For the test case I took CNN.com’s HTML source, consisting of 1,364 HTML elements. I added class names and data attributes to all div‘s and li‘s (after first removing the ones already in place), totaling 751 HTML elements. The code I inserted looks like this: class="gender male age age-9" data-gender="male" data-age="9". The class names and values for the data-gender data attributes (male and female) alternate, so there are 376 elements for males and 375 or females. I ended up not using the ages for this test, but feel free to reuse if you want to test finding age ranges for instance. The ages run from 1 to 10 and aren’t evenly distributed.

Because I didn’t want people to run three test cases separately, I implemented 6 tests to satisfy my curiosities. Only two of them I consider to be relevant for this case, so I’ll only discuss $('.gender.male') vs $('[data-gender="male"]').

In this case I’m using jQuery to find all people of the male gender. I’m using the combination of two class names, as opposed to just .male, because I’m trying to mimic the key/value combination that the data attribute brings to the table. That seemed fair to me.

The jsPerf test determines how often per second it can perform both of the above operations. It does so by running the test multiple times, coming up with an average. This is dependent on device, operating system and browser. A faster laptop will yield more operations per second, which is why it’s great that so many people participated, averaging the results.

The results

Without further ado, here are the most significant results (ordered by number of test runs and OS):

Browser Test runs Ops/sec class name Ops/sec data attribute Slower by
Chrome 21.0.1180 41 1,003 934 6.88%
Safari 6.0 18 612 594 2.94%
Firefox 14.0.1 15 434 404 6.91%
iPhone iOS 5.1.1 6 54 51 5.56%
iPad iOS 5.1.1 5 59 55 6.78%
Android 4.0.4 1 63 56 11.11%
Android 3.2 3 26 25 3.85%
IE 9.0.6 (Windows Phone) 4 31 16 48.39%
IE 9.0 3 337 111 67.06%
IE 8.0 2 261 105 59.77%
IE 7.0 2 2 1 50%
BlackBerry 7.1.0 2 33 32 3.03%

These are the most used or exotic browsers. Finding elements by data attribute is slower, but the speed decrease doesn’t worry me. First, it’s a relatively small difference. On the major modern browsers (Chrome, Safari & Firefox) it’s at most 6.9% slower. That doesn’t sound like much by itself, and even less so considering this still handles at least 404 operations per second (double that for Chrome). That’s finding 376 elements in a DOM of 1,364 elements in 2.5 milliseconds in the slowest browser of the three (1 millisecond in Chrome).

Finding elements by data attribute is slower on handheld devices, for obvious reasons. iOS is 6.2% slower on average. Android is 3.9% or 11.1% slower, but I guess this relies heavily on the device used in combination with the OS version. Some of the Android tests were run on the cheapest and slower models out there, all from our Open Test Lab. Still, the slowest Android takes only 40 milliseconds for the operation. Surprisingly, BlackBerry sees hardly any difference in speed between the two approaches. Windows Phone: 63 milliseconds per operation.

Conclusion

Is it slower? Yes. Is it much slower? It depends, but in general: no. Should you avoid using data attributes in favor of class names because it’s slower? No!