2014. 9. 16. 22:32ㆍ개발/javascript
The classList API
I have to be honest with you: I feel like a fraud writing about JavaScript for HTML5 Doctor. I would feel like a fraud writing about JavaScript for a click-driven ad-splattered content farm, never mind HTML5 Doctor.
The thing is though, I’m writing about the classList
API, and it’s super easy. If your JavaScript-fu isn’t great and you’re wary of HTML5 APIs, this one is at the perfect temperature for toe-dipping, and it’ll leave you pleasantly surprised at just how easy it is.
The classList
API is a “does exactly what it says on the tin” API. It gets a list of the classes on an HTML element and uses JavaScript to manipulate it.
Before this nugget of HTML5 came along, working with classes was a royal pain, but what was once a twisty overgrown cowpath with wolves lurking in thickets is now a bright sunlit path fit for rollerskating.
Getting the classList #
Getting the classList
is a simple matter of element.classList
, like so:
That will log something like ["oh", "my", "giddy", "aunt"]
. The output style varies between browsers, but it will be an object containing a list of the classes on the element.
More accurately, it’s an object that stringifies to the value of the class attribute on the element in question. Try it yourself with the console open.
There is no specification for classList
per se (it gets a sentence in the DOM4 spec), but there is for DOMTokenList
, which is classList
‘s type, so look at the DOMTokenList
specification to find out how to work with lists of classes.
The Type of classList #
If you’re looking to confirm the type of classList
, you’ll need to doelement.classList instanceof DOMTokenList
, which returnstrue
. typeof element.classList
returns “object”, which, given that everything in JavaScript is an object, isn’t particularly informative.
Doing Things with our List of Classes #
The DOMTokenList
spec provides a number of methods that can be used on the classList
:
add()
for adding a class to the listremove()
for removing a class from the listcontains()
to check if a class is in the listtoggle()
for toggling a class in and out of the list (with a twist)item()
to return the class at a specified position in the listtoString()
for turning the list into a stringlength
to return the number of classes in the listvalue
to add custom properties and methods to theclassList
object
classList.add() #
It couldn’t be easier to add a class to an element. Just supply the class you want to add as an argument to the add()
method.
If you view the demo and look at the opening <p>
tag in your favourite inspector before and after pressing the button, you’ll see it change from <p id="bad-joke" class="oh my giddy aunt">
to <pid="bad-joke" class="oh my giddy aunt beryl">
.
Adding a class to the <p>
is all done with that one line. No need to inject inline styles or anything messy like that.
The corresponding classList
object is:
classList.remove() #
Removing a class is just as easy. joke.classList.remove('beryl')
brings us back to where we started.
Adding and Removing Multiple Classes #
The DOMTokenList
spec refers to “tokens”, plural when describing how the add()
and remove()
methods should be run.
The add(tokens…) method […] If one of tokens is the empty string […] If one of tokens contains any ASCII whitespace […] For eachtoken in tokens
No browser so far has implemented a native method of adding/removing more than one class at a time, but it’s trivial to extend the DOMTokenList
object prototype with a hand rolled function:
It’s possible to add and remove multiple classes in the Blink powered browsers with element.classList.add('oh','my')
, and it’s trivial to extend the DOMTokenList
object prototype with a hand rolled function until support is more widespread:
Thanks to David and Kalley for pointing that out in the comments.
Same goes for remove:
Here’s a demo where you can add and remove multiple classes at once.
A bug was filed in 2011 (against a document that no longer exists) suggesting allowing a space separated list or an array inclassList.add()
and classList.remove()
.
The use of the plural “tokens” could be interpreted as allowing an array, but it doesn’t work. InvalidCharacterError
is still specified as the exception to throw if there are any spaces in “tokens”, so that’s definitely not going to work.
If you want to replace an entire classList
with a completely different set of classes, you could use these two functions.
classList.contains() #
This method returns a Boolean true
or false
when checking for the presence of a class in the list.
In our example:
contains()
is useful for checking if a class is in a list before performing an action that depends on its presence (or otherwise):
We can use contains()
to make our previous functions for adding and removing multiple classes better by ensuring they do not try to add duplicate classes on the element or remove classes that don’t exist on it:
and:
classList.toggle() #
For most use cases, classList.toggle()
is very straightforward too. Typically, an action by the program or the user will trigger a function that adds or removes a class depending on whether it’s already in the list.
A simple show/hide is a good example of this:
View a demo of a two-level menu that takes up a little less room in smaller viewports by using classList.toggle()
to enhance sub-menus.
force #
There’s a little twist to toggle()
, though. It can take an optional second parameter, force
.
If force
is set to true
, the class will be added but not removed. If it’sfalse
, the opposite will happen — the class will be removed but not added.
Now that sounds a lot like add()
and remove()
, but there is a crucial difference: toggle()
with force
returns true
when a class is added, and false
when it’s removed — add()
and remove()
returnundefined
.
At the time of writing, only the Blink powered browsers honour theforce
parameter, so view the demo with true and the demo with falsein Opera 15, Opera for Android, or the latest Chrome to see it working.
Browsers that don’t support force
completely ignore it and merrily toggle the class name on and off without throwing exceptions.
When it’s more widely supported, we can use a slightly leaner syntax for ensuring the presence or absence of a class in the list. Instead of:
we could write:
classList.item() #
The item()
method can be found elsewhere in JavaScript, usually on NodeList objects. It returns the value of the item at index
counting from zero.
In our example:
classList.item()
cannot be used for assignment, sojoke.classList.item(3) = 'uncle'
will throw an error.
If you were hoping classList.item()
could assign values to items at specific positions in the list, I’m afraid you’ll be disappointed. There’s no DOMTokenList
method that gives that level of control over the list.
classList.toString() #
If you ever need the classList
turned into a string use this method.toString()
is another built in JavaScript method that isn’t specific toDOMTokenList
.
All the W3C spec says on the subject is that DOMTokenList objects must stringify to the underlying string.
WHATWG leaves it at The stringifier must return the result of the set serializer for the associated list of tokens.
The only difference between the two is the amount of plain English used.
It takes no parameters when used with classList
and returns all the classes on the element as a space separated string:
classList.length #
length
is also a built-in JavaScript property. It returns the number of characters in a string, the number of items in an array, the number of arguments expected in a function, or (in our case) the number of classes in classList
. In our example using “oh my giddy aunt”, it’s 4
.
Simple and obvious, hopefully.
classList.value #
On their own, the item()
, toString()
, and length
methods aren’t especially useful. They can, however, be used in conjunction with each other and the rest of the methods of DOMTokenList
to solve some of the problems I mentioned earlier.
Remember that classList
is a regular JavaScript object, so we can add properties to it the same as any other object:
And of course we can add methods. Here’s a method that replaces the entire list with a new one using length
, toString()
, add()
, andremove()
:
And here’s a method that inserts a class in any position in the list you want. It uses contains()
, item()
, remove()
, toString()
, and thereplace()
method we just made:
Being realistic, methods like these would probably be better used to extend DOMTokenList
like we did with addmany()
andremovemany()
, but if you ever need something specific to a particularclassList
you’re working on, you can use value
.
Browser Support and Polyfills #
The classList
API works in pretty much every up-to-date browser version. Basic support at least has been in since Firefox 3.6, Opera 11.50, Chrome 8, and Safari 5.1.
The big holes are IE9 and earlier and the still widely used Android 2.3and earlier.
There are at least two polyfills available that can fill these holes.
Devon Govett’s was written quickly to add support to IE9 only, and it’s worth reading the comments for some good cross-browser JavaScript info.
Eli Grey’s polyfill has wider browser support. It works in IE8, and it provides basic classList.add()
, classList.remove()
, andclassList.toggle()
support to at least as far back as Android 2.1.
There’s also a polyfill for adding force
support by Егор Халимоненкоto browsers that support classList
but not force
on toggle()
.
If you only need a simple feature test you can use:
Summary #
You can think of the classList
API on two levels. For most uses, it’s a simple way to add, remove, toggle, and check for the presence of single classes in an HTML element. I use it in every project I work on now and very rarely need to stray beyond these basic methods. I can’t think of any use for item()
, length
, or toString()
as stand-alone methods, so don’t fret about them.
On another level, it’s about objects, it’s about finding powerful ways to manipulate the state of web pages, it’s about separation of concerns, it’s about progressive enhancement.
How far you take it is up to you, but as I said at the start, it’s an easy one to get into and makes what was hard, easy. I encourage you to take what I’ve written here and experiment in your own projects if you’re new to it, and take to the comments to tell me where I could have said it better if you’re already familiar with it.
'개발 > javascript' 카테고리의 다른 글
Javascript Python Logo (0) | 2024.12.16 |
---|---|
$.ajax beforeSend (0) | 2014.01.12 |
날자 객체 Date Object (0) | 2014.01.05 |
Google maia.js - the "Twitter Bootstrap" made by Google with Closure (0) | 2013.09.04 |
[canvas] 간단히 만들어보는 HTML5 애니메이션 (0) | 2013.08.25 |