Multi Column List with jQuery

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.

cdl_capture_2012-01-30-25_ 000

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.

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

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

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

  4. 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.

 

http://codeasily.com/jquery/multi-column-list-with-jquery

Leave a Reply