I’ve spent a rainy german saturday hacking away on my dusty ol' website. Because of the current layout without sidebars, I had to find an unobtrusive place for meta-information like tags or archive-links. Those chunks of information can grow quite large, so i decided to expand into length rather than height and go multi-column for longer lists. Before I fully understood the stony way that lay before me, I’ve found an article on “A List Apart”-magazine outlining different ways to tackle this problem. Because of lacking support for true multi-columns we have to resort to some slightly hacky CSS, either floating or applying negative margins.
My solution works with negative margins, but automatically applied through a JQuery-plugin (see example below). It seems to be rather stable across browsers, but has the usual quirks of using CSS for something its not intended to perform - make sure to read about the CSS-limitations of this method over at “A List Apart”. By the way, you can see this plugin in action through the “archive”-area at the top of this website
Features
- Styling of ordered/unordered lists
- Configurable column-count and width
- Resize-friendly em-based sizing
- Easy restoring to “non-column” layout
- Automatic adjustment on DOM-modification of the list (Firefox only)
- Requirements: JQuery 1.2 (download)
- Browser-Compatibility: Firefox 1.5+, IE6+, Safari 2
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).
$('#demolist').columnizeList({cols:3,width:13,unit:'em'});
Example
- float / unfloat (Lame! List-ordering is messed up)
- columnizeList() / uncolumnizeList() (The real deal)
- harold (3550)
- horatio (1320)
- hitler (1120)
- henry (784)
- hector (358)
- haploid (315)
- hopping (50)
- herbert mulroney (44)
- hopscotching (29)
- hominibus (19)
- honkey (19)
- hermoine (18)
- hieronymus (13)
- halliburton (12)
- hummer (10)
- harlod (10)
- heironymious (9)
- hemorrhoids (7)
- hammersack (6)
Just in case you’re wondering: The demo-list consists of the most common fillers for the phrase “Jesus H Christ” ;-)
Sourcecode
/**
* Copyright (c) 2007 Ingo Schommer (www.chillu.com)
* Licensed under the MIT License:
* http://www.opensource.org/licenses/mit-license.php
*
* Splits a /-list into equal-sized columns.
*
* Requirements:
*
* All list-elements need to have the same height.
* List has to be blocklevel
*
*
* Caution: margin-top/margin-left on are overridden.
* Doesn't react to changes to the DOM, you need to call the function
* manually afterwards.
*
* @see http://www.alistapart.com/articles/multicolumnlists
*/
jQuery.fn.columnizeList = function(settings){
settings = jQuery.extend({
cols: 3,
width: '13',
unit: 'em'
}, settings);
var prevColNum = 0;
var size = $('li',this).size();
var computedColHeight = 0;
var baseFontSize = parseFloat($(this).css('font-size'));
$('li',this).each(function(i) {
var currentColNum = Math.floor(((i)/size) * settings.cols);
$(this).css('margin-left',(currentColNum*settings.width)+''+settings.unit);
if(prevColNum != currentColNum) {
$(this).css('margin-top','-'+(computedColHeight/baseFontSize)+'em');
computedColHeight = $(this).height();
} else {
$(this).css('margin-top','0');
computedColHeight += $(this).height();
}
prevColNum = currentColNum;
});
this.css('height',(size/settings.cols)*(parseFloat($('li:first',this).height())/baseFontSize)+'em');
this.after('');
var onchange = function(e) {
if(!e.originalTarget || e.originalTarget.tagName != 'LI') return true;
var scope = this; // caution: closure
setTimeout(function() {$(scope).columnizeList(settings);}, 50);
};
this.one('DOMNodeInserted',onchange);
this.one('DOMNodeRemoved',onchange);
return this;
};
jQuery.fn.uncolumnizeList = function(){
$('li',this).each(function(i) {
if(!$(this).attr('style')) return;
$(this).attr('style',
$(this).attr('style')
.replace(/margin\-left[^,]*/g,'')
.replace(/margin\-top[^,]*/g,'')
);
});
$('ul',this).each(function(i) {
if(!$(this).attr('style')) return;
$(this).attr('style',
$(this).attr('style')
.replace(/[^-]height[^,]*/g,'')
);
});
$(this).height('auto');
this.unbind('DOMNodeInserted');
this.unbind('DOMNodeRemoved');
return this;
}