I want to show list items as 2 or more columns (dynamic alignment)

I am able to do the list using float:left; like this

enter image description here

But I would like to show it like this (as 2 or more columns)

enter image description here

How can I do that?

@sandeep gave good solution. Unfortunately does not work in IE(need ie7 and above).

any help?


Solution 1:

For this, you can use the column-count property:

div#multicolumn1 {
    -moz-column-count: 2;
    -moz-column-gap: 50%;
    -webkit-column-count: 2;
    -webkit-column-gap: 50%;
    column-count: 3;
    column-gap: 50%;
}

Check this jsFiddle.

Note: It does not work in IE.

For IE, you can use this JavaScript: CSS3 - Multi Column Layout Demonstration

Solution 2:

This works just fine cross-browser, no JS required. You just limit the width of your columns.

<style>
    ul.col {width:60px;float:left;margin:0 5px 0 0;padding:0;}
    ul.col li {width:50px;background:#999;list-style-type:none;margin:0 0 5px 0;padding:5px;}
</style>

<ul class="col">
    <li>1(li)</li>
    <li>2(li)</li>
    <li>3(li)</li>
    <li>4(li)</li>
    <li>5(li)</li>
</ul>
<ul class="col">
    <li>6(li)</li>
    <li>7(li)</li>
    <li>8(li)</li>
    <li>9(li)</li>
    <li>10(li)</li>
</ul>

If you are stuck with them all in one UL on page load, you can split them out with jQuery to create the same results:

<script>
$(function(){ //on document ready
    var perCol = 5;
    var $ul = $('ul.col');
    var rows = Math.ceil($ul.find('li').length/perCol);
    for(var i=1;i<=rows;i++){
        $ul.after('<ul class="col"></ul>');
    }
    for(var i=1;i<=rows;i++){
        $ul.find('li:lt('+(perCol)+')').appendTo('ul.col:eq('+(i)+')');
    }
    $ul.remove();
});
</script>

Solution 3:

As long as your list items are a fixed width, like in your examples, couldn't you just do something like in this fiddle? http://jsfiddle.net/swNYE/1/

And wherever your list gets spit out, simply apply the "left" class to the first half, and the "right" class to the second half. If you're dynamically adding content through Javascript, then you'd simply run through the li's each time something is added, and apply the new correct class.

HTML:

<ul>
    <li class="left">1</li>
    <li class="left">2</li>
    <li class="left">3</li>
    <li class="left">4</li>
    <li class="right">5</li>
    <li class="right">6</li>
    <li class="right">7</li>
    <li class="right">8</li>
</ul>

CSS:

li {
    width: 100px;
}
li.left {
    float: left;
    clear: left;
}
li.right {
    margin-left: 100px;
}

Solution 4:

Below is a columnizer, takes as argument the number of columns.

Call: $(elem).columnize(3)

http://jsfiddle.net/Bdsj9/28/

Tested in IE6 from wine in Ubuntu 10.04: works (looks better if you increase the width in the stylesheet I borrowed from @micha -- thanks, btw)

(function($) {
    $.fn.decolumnize = function() {
        this.children().map(function(index, el) {
            var oldPos = null;
            var posClass = null;
            if($(el).attr("class") && (posClass = $(el).attr("class").match(/orig\-readorder\-[0-9]+/))) {
                oldPos = parseInt(posClass[0].replace("orig-readorder-", ""));
                $(el).removeClass(posClass[0]);
            }
            return {
                elm: el,
                pos: oldPos ? oldPos : index
            }
        }).sort(function(a,b) {
            return a.pos > b.pos ? 1 : -1;
        }).map(function(index, ob) {
            return ob.elm;
        }).appendTo(this);
        return this.children().css("float", "left").css("clear", "none");
    };
    $.fn.columnize = function(numcols) {
        var numItems = this.children().length;
        var divisor = Math.ceil(numItems / numcols);
        var indexOfFinal = null;       
        this.decolumnize();


        var resorted = this.children().map(function(index, el) {
            return {
                position: (index % divisor) + (index / numItems),
                elm: el,
                isFinal: index == numItems - 1,
                origPos: index
            };
        }).sort(function(a, b) {
            return a.position > b.position ? 1 : -1;
        });
        return resorted.map(function(index, ob) {
            if (indexOfFinal) {
/** TODO: fix redundancy  **/
                if ((index - indexOfFinal - 1) % (numcols - 1) == 0) {
                    if ($.browser.msie && resorted[index - 1]) $(resorted[index - 1].elm).css("float", "none");
                    $(ob.elm).css("clear", "left");
                }
            } else {
/** TODO: fix redundancy **/
                if (index % numcols == 0) {
                    if ($.browser.msie && resorted[index - 1]) $(resorted[index - 1].elm).css("float", "none");
                    $(ob.elm).css("clear", "left");
                }
            }

            if (ob.isFinal) indexOfFinal = index;
            $(ob.elm).addClass("orig-readorder-" + ob.origPos);
            return ob.elm;
        }).appendTo(this);
    };
})(jQuery);

What it does is first calculate the sortorder, because with just styling this will not work. To calculate the sortorder you need to know the number of columns up front. This you can use as a divisor to introduce a 'clear: left'.

Also, using the number of list items and the number of columns you need to estimate a number of rows. This can be used as a divisor to sort the items based on the remainer between their index and the number of rows.

To granulate the sortation, the original index is also taken into account...

After the last orginal item has been placed, the number of columns needs to be reduced by 1. That's why I store the isFinal-boolean. I'm sure this could be done more elegantly with some smart computation, though.

Then introduce the 'clear: left's at the right place and store the original position in a class so you can resort in a later stage (for instance when inserting or removing a list item dynamically)

Best!

Solution 5:

I found a way to do this in IE too. (using clear)

html:

<div class="left child">1</div>
<div class="child">5</div>
<div class="left child">2</div>
<div class="child">6</div>
<div class="left child">3</div>
<div class="child">7</div>
<div class="left child">4</div>
<div class="child">8</div>

css:

.child {
    height:20px;
    width: 20px;
    text-align: center;
    border: 1px solid #CCC;
    background-color: #EEE;
    color: #000;
    padding: 5px;
    float: left;
    margin: 5px;
}
.left {
    clear: left;
}

See http://jsfiddle.net/pMbtk/31/