Don’t forget to read the follow-up too!
rel attribute). After all, using a class name won’t invalidate your HTML, is easy to target (specially with a library such as jQuery) and provides a hook for styling. But those days are over with the introduction of better suitable techniques, and using class names to find elements leads to confusion and maintenance issues. For true separation of styling and behavior you should use custom data attributes instead, with added benefits.
It’s not “wrong”
In the sense of “not being according the specifications” it isn’t wrong (when using HTML5). In the HTML4 specification the W3C is clear on the intended use of the
class attribute, saying it should be used “as a style sheet selector (when an author wishes to assign style information to a set of elements).” The HTML5 specification on the other hand, says: “Assigning classes to an element affects class matching in selectors in CSS, the
getElementsByClassName() method in the DOM, and other such features.” So when writing HTML5, you’re creating completely valid code.
Imagine a situation where you want to apply some interaction to a list of people in various age groups. You have groups of 0 to 9 and 10 to 19 year olds. In your HTML you use
class="10-19". Now you can find all elements belonging to the group of 0 to 9 year olds with
$('.0-9') (jQuery syntax), so you can bind an
onclick event to them. After a while you decide it’s fun to style all children with a playful icon, so in your CSS you add a background image for any elements having the
After a while you’re replaced or a new developer is added to the team, and the project owner says he would like that little icon we show for small kids to be visible for everyone up to 12 years of ago. Piece of cake for the new guy: just rename the class name
0-9 to the more generic
kid in the CSS and make sure the HTML reflects all children up to 12 use this new class name. From all other elements the
10-19 class can be removed; it’s inaccurate and not used anyway. Your new guy or girl reloads the page and sees it’s all good.
$('.0-9'). Sure you could expect your developers to hit every single element after making a trivial change, but that would be too expensive (and you know they won’t anyway).
$('.kid') doesn’t work, as it finds more than just children up to 9 years old. Time to add a second class name, reinstating the previous structure. Congratulations: you’ve spent over an hour on essentially adding
kid as a second class name to some elements.
Time to really start separating structure, styling & behavior
onclick attributes in your HTML; separation of structure and behavior is important for various reasons. Of course your HTML and CSS need to be linked in some form, as do your HTML and JS. But can targeting elements based on their class name really be considered separation between styling and behavior? You’re tying all three layers together, leading to the issues outlined above.
Use custom data attributes instead of class names
kid class name for the background image and add
$('[data-age-group="0-12"]'), or if you want any element with a certain data attribute regardless of value,
$('[data-age-group]') (this works in IE6 when using jQuery or the
Key/value pairs have more semantic meaning
You’ll gain more semantic meaning when using data attributes. Where “0-9” could mean basically anything, “age-group” is quite clear on what its value is about. It enables you to add a similar metric later, without refactoring. If you want to add the number of pets someone owns you can just add
data-pets="0-9". When using class names, you would have to refactor your
0-9 to something like
pets-0-9 as a second class name.
Data attributes enable a modular approach
data-carousel-items="2" to your
<ul>. Your script can find all elements with that attribute and use their values to determine how many items to show at a time, doubling as a config option. It doesn’t require any change in the HTML apart from adding that attribute and the CSS can remain untouched.
Let’s make this a best practice.
Update: It’s slower, and that doesn’t bother me
As discussed in the comments, looking up elements by data attribute in jQuery is slower than by class name. In this jsPerf test the
$('.class') operation can be performed ± 124,000 times per second. The
$('data-foo="bar"']) operation only ± 26,000 times (tested on Chrome). Yes, it’s over 70% slower. No, it isn’t slow. Imagine there are 2,500 elements to search through; it will take under 100 milliseconds. IE sucks of course, with IE9 handling only just over 7,000 operations/second (sorry for the wait). It works for me.