Log
Splitting Lists into Two Columns with Javascript
Inspired by A List Apart’s article Bulleted Lists: Multi-Layered Fudge, I decided that a better way to make a two column list is with Javascript. That way, the markup doesn’t get polluted with extra non-semantic lists. All that is needed with my approach, which could be easily adapted, is a class on each list to be converted to two columns.
The javascript:
function twoCols(src, type)
{
var origList = src;
var leftList = document.createElement(type);
var rightList = document.createElement(type);
var container = document.createElement('div');
var items = origList.getElementsByTagName('LI');
var itemsLength = items.length/2;
for (i = 0; i < itemsLength; i++)
{
leftList.appendChild(items[0]);
}
itemsLength = items.length;
for (i = 0; i < itemsLength; i++)
{
rightList.appendChild(items[0]);
}
container.appendChild(leftList);
container.appendChild(rightList);
leftList.setAttribute('class', 'left');
rightList.setAttribute('class', 'right');
container.setAttribute('class','twocol');
if (document.all)
{
leftList.setAttribute('className', 'left');
rightList.setAttribute('className', 'right');
container.setAttribute('className','twocol');
}
if (type == 'ol')
{
rightList.setAttribute('start', leftList.getElementsByTagName('LI').length + 1 );
}
origList.parentNode.replaceChild(container, origList);
}
function allTwoCols (whichclass, type)
{
var uls = document.getElementsByTagName(type);
for (var i=0; i< uls.length; i++)
{
if (uls[i].getAttribute('class') == whichclass ||
uls[i].getAttribute('className') == whichclass)
{
twoCols(uls[i], type.toLowerCase());
}
}
}
The css:
div.twocol ul, div.twocol ol {
float: right;
width: 40%;
margin: 0;
padding: 0;
list-style-position: inside;
}
div.twocol ul {
list-style-type: square;
}
div.twocol .left {
float: left;
position: relative;
}
div.twocol {
margin: 0;
padding: 0;
}
To convert your lists:
allTwoCols('two', 'UL');
allTwoCols('two', 'OL');
The css was explained well in the ALA article, so let’s take a look at the javascript. The function twoCols
does the real real work in converting the list to two columns. It takes two arguments: src
and type
. The first, src
, is a reference to the list you want to convert. The second, type
, accepts to possible values: “UL” and “OL”. We start out by using the createElement
method to create new elements: two new lists and a div to hold them. We then populate a new array, items
, with the existing list items: var items = origList.getElementsByTagName('LI');
.
The next bit of code is breaks the list items in half and appends them to the two new lists:
var itemsLength = items.length/2;
for (i = 0; i < itemsLength; i++)
{
leftList.appendChild(items[0]);
}
itemsLength = items.length;
for (i = 0; i < itemsLength; i++)
{
rightList.appendChild(items[0]);
}
Here’s the tricky part: we need to look at the number of items in the items
array before we add them to the new lists. That’s because the appendChild
method removes the item from the array. For the same reason, we use the first item in the items
array (items[0]
). Doing this also maintains the original order of the list items.
Initially, we set the variable itemsLength
to be half the number of items because we only want the first half. We also assume that if there’s an odd number of list items, the left hand column will have the extra one. After we build the left list, we need to reset the value of itemsLength
because we want to get all of the remaining list items.
Next, attach the new lists to the div:
container.appendChild(leftList);
container.appendChild(rightList);
Next, add class names to the new items. Internet Explorer requires that you use the className
attribute to apply a class to an element, so we filter for IE with document.all
.
leftList.setAttribute('class', 'left');
rightList.setAttribute('class', 'right');
container.setAttribute('class','twocol');
if (document.all)
{
leftList.setAttribute('className', 'left');
rightList.setAttribute('className', 'right');
container.setAttribute('className','twocol');
}
Next, if the list is an ordered list, we need to start the right hand list with a logical number, so we add the start attribute with a value that is calculated by grabbing the number of items in the left hand list and adding one.
if (type == 'ol')
{
rightList.setAttribute('start', leftList.getElementsByTagName('LI').length + 1 );
}
Then we replace the original list with the new div that we created:
origList.parentNode.replaceChild(container, origList);
The hard part’s done. The allTwoCols
function loops through our document and converts all the lists that match our class and our type, either “UL” or “OL”.
The first line grabs all the lists matching the type and stuffs them into an array called “uls”. Then it loops through and compares each list’s class to the class we specified, again using an or operator to check for IE. If the class matches, we call the twoCols
function.
function allTwoCols (whichclass, type)
{
var uls = document.getElementsByTagName(type);
for (var i=0; i< uls.length; i++)
{
if (uls[i].getAttribute('class') == whichclass ||
uls[i].getAttribute('className') == whichclass)
{
twoCols(uls[i], type.toLowerCase());
}
}
}
Works like a charm in Safari, Firefox, and IE. It probably works in other too, I just haven’t had a chance to test it.
02/17/05 04:51PM Design Geekiness
Comments
Add a Comment
Have something to say about what I wrote here? Let’s hear it!
- Your name and email address are required, but your email will not be displayed on the site
- If you provide a URL, a link to your site will appear
- You may use the following HTML:
<strong>
bold</strong>
<em>
italic</em>
<a href="http://url">
links</a>
- Double line breaks will be converted to paragraphs.
- As you type, you should get a nice little preview of your comment directly below the text box.
- I reserve the right to edit any comment for any reason (I’ll be reasonable).
Recently Played on iTunes
-
“Argument”
Argument
Fugazi
16:47 02/21/05 -
“When The Angels Sing”
White Light, White Heat, White Trash
Social Distortion
16:43 02/21/05 -
“Skink”
Experimental Jet Set, Trash And No Star
Sonic Youth
16:39 02/21/05