So I needed a method to take a long, nested list and turning it into a compact, multiple acolumn list, for example, in order to display it as sort of a site map.

Being a huge fan of jQuery, it was naturally my go-to library of choice.

Scanning the plugins site, I can’t find a fair solution.

One of the caveats of many methodologies is that each list item has to be the same height. This works Ok for a lot of use cases, but what if your the source for the list contain arbitrary text you don’t control.

So, I started from scratch. Instead of relying on consistent line heights, and applying different margin settings to list elements, I decided to decompose the large source list into several smaller lists (one for each column) and then use a css float parameter to make them all appear side-by-side.

Features

  • Styling of ordered/unordered lists
  • Configurable column-count and width
  • Easy restoring to “non-column” layout
  • Requirements: JQuery 1.2 (download)
  • Browser-Compatibility: Firefox 1.5+, IE6+, Safari 2, Opera 9+


Usage

Just apply to any group of DOM-elements gathered by the amazing JQuery-selectors. The provided arguments are optional (these are the default values).

$('ol').makeacolumnlists({cols:2,colWidth:0,equalHeight:false,startN:1});

Example

Columnize / Uncolumnize (equalHeight: ‘ol’)

  1. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.

  2. Cras vitae libero. Duis sed pede id erat laoreet varius.

  3. Ut arcu mauris, blandit at, porttitor vel, scelerisque vitae, nunc.

  4. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.

  5. Cras vitae libero. Duis sed pede id erat laoreet varius.

  6. Ut arcu mauris, blandit at, porttitor vel, scelerisque vitae, nunc.

  7. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.

  8. Cras vitae libero. Duis sed pede id erat laoreet varius.

  9. Ut arcu mauris, blandit at, porttitor vel, scelerisque vitae, nunc.

Sourcecode

/** 
#  * Copyright (c) 2008 Pasyuk Sergey (www.codeasily.com) 
#  * Licensed under the MIT License: 
#  * http://www.opensource.org/licenses/mit-license.php 
#  *  
#  * Splits a <ul>/<ol>-list into equal-sized columns. 
#  *  
#  * Requirements:  
#  * <ul> 
#  * <li>"ul" or "ol" element must be styled with margin</li> 
#  * </ul> 
#  *  
#  * @see http://www.codeasily.com/jquery/multi-column-list-with-jquery 
#  */  
jQuery.fn.makeacolumnlists = function(settings){
	settings = jQuery.extend({
		cols: 3,		// set number of columns
		colWidth: 0,		// set width for each column or leave 0 for auto width
		equalHeight: false, 	// can be false, 'ul', 'ol', 'li'
		startN: 1		// first number on your ordered list
	}, settings);
 
	if(jQuery('> li', this)) {
		this.each(function(y) {
			var y=jQuery('.li_container').size(),
		    	height = 0, 
		        maxHeight = 0,
				t = jQuery(this),
				classN = t.attr('class'),
				listsize = jQuery('> li', this).size(),
				percol = Math.ceil(listsize/settings.cols),
				contW = t.width(),
				bl = ( isNaN(parseInt(t.css('borderLeftWidth'),10)) ? 0 : parseInt(t.css('borderLeftWidth'),10) ),
				br = ( isNaN(parseInt(t.css('borderRightWidth'),10)) ? 0 : parseInt(t.css('borderRightWidth'),10) ),
				pl = parseInt(t.css('paddingLeft'),10),
				pr = parseInt(t.css('paddingRight'),10),
				ml = parseInt(t.css('marginLeft'),10),
				mr = parseInt(t.css('marginRight'),10),
				col_Width = Math.floor((contW - (settings.cols-1)*(bl+br+pl+pr+ml+mr))/settings.cols);
			if (settings.colWidth) {
				col_Width = settings.colWidth; 
			}
			var colnum=1,
				percol2=percol;
			jQuery(this).addClass('li_cont1').wrap('<div id="li_container' + (++y) + '" class="li_container"></div>');
			if (settings.equalHeight=='li') {
			    jQuery('> li', this).each(function() {
			        var e = jQuery(this);
			        var border_top = ( isNaN(parseInt(e.css('borderTopWidth'),10)) ? 0 : parseInt(e.css('borderTopWidth'),10) );
			        var border_bottom = ( isNaN(parseInt(e.css('borderBottomWidth'),10)) ? 0 : parseInt(e.css('borderBottomWidth'),10) );
			        height = e.height() + parseInt(e.css('paddingTop'), 10) + parseInt(e.css('paddingBottom'), 10) + border_top + border_bottom;
			        maxHeight = (height > maxHeight) ? height : maxHeight;
			    });
			}
			for (var i=0; i<=listsize; i++) {
				if(i>=percol2) { percol2+=percol; colnum++; }
				var eh = jQuery('> li:eq('+i+')',this);
				eh.addClass('li_col'+ colnum);
				if(jQuery(this).is('ol')){eh.attr('value', ''+(i+settings.startN))+'';}
				if (settings.equalHeight=='li') {
			        var border_top = ( isNaN(parseInt(eh.css('borderTopWidth'),10)) ? 0 : parseInt(eh.css('borderTopWidth'),10) );
			        var border_bottom = ( isNaN(parseInt(eh.css('borderBottomWidth'),10)) ? 0 : parseInt(eh.css('borderBottomWidth'),10) );
					mh = maxHeight - (parseInt(eh.css('paddingTop'), 10) + parseInt(eh.css('paddingBottom'), 10) + border_top + border_bottom );
			        eh.height(mh);
				}
			}
			jQuery(this).css({cssFloat:'left', width:''+col_Width+'px'});
			for (colnum=2; colnum<=settings.cols; colnum++) {
				if(jQuery(this).is('ol')) {
					jQuery('li.li_col'+ colnum, this).appendTo('#li_container' + y).wrapAll('<ol class="li_cont'+colnum +' ' + classN + '" style="float:left; width: '+col_Width+'px;"></ol>');
				} else {
					jQuery('li.li_col'+ colnum, this).appendTo('#li_container' + y).wrapAll('<ul class="li_cont'+colnum +' ' + classN + '" style="float:left; width: '+col_Width+'px;"></ul>');
				}
			}
			if (settings.equalHeight=='ul' || settings.equalHeight=='ol') {
				for (colnum=1; colnum<=settings.cols; colnum++) {
				    jQuery('#li_container'+ y +' .li_cont'+colnum).each(function() {
				        var e = jQuery(this);
				        var border_top = ( isNaN(parseInt(e.css('borderTopWidth'),10)) ? 0 : parseInt(e.css('borderTopWidth'),10) );
				        var border_bottom = ( isNaN(parseInt(e.css('borderBottomWidth'),10)) ? 0 : parseInt(e.css('borderBottomWidth'),10) );
				        height = e.height() + parseInt(e.css('paddingTop'), 10) + parseInt(e.css('paddingBottom'), 10) + border_top + border_bottom;
				        maxHeight = (height > maxHeight) ? height : maxHeight;
				    });
				}
				for (colnum=1; colnum<=settings.cols; colnum++) {
					var eh = jQuery('#li_container'+ y +' .li_cont'+colnum);
			        var border_top = ( isNaN(parseInt(eh.css('borderTopWidth'),10)) ? 0 : parseInt(eh.css('borderTopWidth'),10) );
			        var border_bottom = ( isNaN(parseInt(eh.css('borderBottomWidth'),10)) ? 0 : parseInt(eh.css('borderBottomWidth'),10) );
					mh = maxHeight - (parseInt(eh.css('paddingTop'), 10) + parseInt(eh.css('paddingBottom'), 10) + border_top + border_bottom );
			        eh.height(mh);
				}
			}
		    jQuery('#li_container' + y).append('<div style="clear:both; overflow:hidden; height:0px;"></div>');
		});
	}
}
 
jQuery.fn.uncolumnlists = function(){
	jQuery('.li_cont1').each(function(i) {
		var onecolSize = jQuery('#li_container' + (++i) + ' .li_cont1 > li').size();
		if(jQuery('#li_container' + i + ' .li_cont1').is('ul')) {
			jQuery('#li_container' + i + ' > ul > li').appendTo('#li_container' + i + ' ul:first');
			for (var j=1; j<=onecolSize; j++) {
				jQuery('#li_container' + i + ' ul:first li').removeAttr('class').removeAttr('style');
			}
			jQuery('#li_container' + i + ' ul:first').removeAttr('style').removeClass('li_cont1').insertBefore('#li_container' + i);
		} else {
			jQuery('#li_container' + i + ' > ol > li').appendTo('#li_container' + i + ' ol:first');
			for (var j=1; j<=onecolSize; j++) {
				jQuery('#li_container' + i + ' ol:first li').removeAttr('class').removeAttr('style');
			}
			jQuery('#li_container' + i + ' ol:first').removeAttr('style').removeClass('li_cont1').insertBefore('#li_container' + i);
		}
		jQuery('#li_container' + i).remove();
	});
}

There are few parameters – cols, the number of columns to break the list into; colWidth set width for each column or leave 0 for auto width; equalHeight (defaulting to false) can be false, ‘ul’, ‘ol’, ‘li’ to set equal height for ul/ol or li elements; startN, the start number of numbered list.

I’ve tested with IE 6&7, FF3, Safari3 and Opera 9. The code could use a bit of refactoring perhaps for the purpose of beautification. View my demo file to see more samples or download
I’ve added this to the jQuery Plugin site.

15 Responses to “Multi Column List with jQuery”

  1. Kyle says:

    Is it possible to have this separate child UL’s as well?

    I have a list that has an integrated sub-list coming from a CMS.
    It should break into three separate equal height columns, but the sub list doesn’t break apart, it stays directly under it’s parent.

    It’s for a footer that will list all pages of the site, any ideas?

  2. baha says:

    Thank you a lot for sharing.

  3. Aldi says:

    Can each point/bullet from the left & the right column from each line be made aligned (while still being fluid)?

    So that, like the example above, no.6 is aligned to no.1, no.7 to no.2, 8 to 3, and so on…

  4. cbp says:

    Brilliant little plugin – worked straight away. Thanks

  5. GianniC says:

    Nice little bugger….worked great!

  6. skybondsor says:

    Fabulous! Thank you!

  7. Peter K says:

    Great plugin. As usual, Firefox implements it without a problem, but there seems to be a bug in IE8 – doesn’t like the 0 colWidth setting for auto width. Putting a colWidth value in seems to fix it.

  8. Jacob says:

    Great plugin! Just what I’ve been looking for.

    Have you, or anyone, had any compatibility problems with IE7 and WordPress? I’m running WP 2.8.6, currently. Works fine IE8, but kills the all of the jQuery loaded on the site in IE7… Good times.

    Thanks!

    Jacob

  9. Nick says:

    This is nice! I’m brand new to jQuery, but I did write a php function to do this with an array of strings, but I’m really digging the ability to apply this “after the fact” with jquery.

  10. Nick says:

    Also, If you remove the px from col_Width, you can allow for more flexibility in constraints, like ‘30%’, or ‘5em’..

  11. Thank you very much. very nice work! worked perfectly .. :)

  12. Nick says:

    If you’re having trouble getting list bullets to show in IE, I’ve found that playing with the left padding of the UL container helps…

    • Ben says:

      Nick, thanks so much for posting this. I’ve spent hours trying to figure out why IE6+7 weren’t showing my list numbers for an . Thanks!!

  13. [...] : http://codeasily.com/ Tags: JavaScript, li, list, menu, multi column, ul Share this [...]

Leave a Reply

Hello :)

You are blocking my beautiful
adverts with AdBlocker!
Disable it for CodEasily.com
if you want to see more articles
and leave comments here.

Thanks!