CSS-centric JS
Thursday, September 11th, 2008This probably isn’t news to anyone deep in JS/CSS land, but I thought these notes may be handy for someone who’s still figuring out the best way to approach some problems.
There’s a temptation, I think, to go overboard with JS when manipulating elements on a page. Many tasks can be more simply handled with a combination of JS and CSS.
For example, let’s say you have a simple unordered list:
<ul id="happyList">
<li><a href="tacos.html">Tacos</a></li>
<li><a href="burritos.html">Burritos</a></li>
<li><a href="enchiladas.html">Enchiladas</a></li>
<li><a href="tamales.html">Tamales</a></li>
<li><a href="chalupas.html">Chalupas</a></li>
<li><a href="antacids.html">Antacids</a></li>
</ul>
Let’s say that you only want 3 items to show by default, and you want a “More” link at the bottom that will expand the list to show the rest.
There’s a few ways you could approach this. People may be tempted to put an onclick event onto the “More” link, then have that call a function that toggles the visibility of each element after the third. Something like:
var happy = document.getElementById('happyList');
var items = happy.getElementsByTagName('li');
function showLinks() {
for (var i=3; i < items; i++) {
items[i].style.display = 'list-item';
}
}
function hideLinks() {
for (var i=3; i < items; i++) {
items[i].style.display = 'none';
}
}
That would work (though I haven’t actually tested this particular js), but it’s definitely the crappy way, for a number of reasons. First, there’s no need for two functions, though that’s beside the point of this post. Second, we’re running through a for() loop every time each function is called.
Instead of something like that, the way I’d do it is to first set up this CSS:
#happyList.collapsed li {
display: none;
}
#happyList.collapsed li.alwaysShow {
display: list-item;
}
Then, you put a class of ‘alwaysShow’ on the first three list item elements, either in the html itself or with javascript:
function assignShow() {
var happy = document.getElementById('happyList');
var items = happy.getElementsByTagName('li');
for (var i=0; i < items.length && i < 3; i++) {
items[i].className = 'alwaysShow';
}
}
Now, when the ul has a class of ‘collapsed’, only the first three items show:
function toggleList() {
var happy = document.getElementById('happyList');
if (happy.className == 'collapsed') {
happy.className = '';
} else {
happy.className = 'collapsed';
}
}
Or, more succinctly:
function toggleList() {
var happy = document.getElementById('happyList');
happy.className = happy.className ==
'collapsed' ? '' : 'collapsed';
}
Then, either in HTML or using javascript, you can add an element with the “More” text and attach an event to it that calls toggleList().
I’m being a little vague on details here. My main point is that it’s preferable to lean on CSS as much as possible. It helps to avoid micromanaging elements.