19

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?

Kyle
  • 65,599
  • 28
  • 144
  • 152
The Unshaped Man
  • 219
  • 1
  • 2
  • 9
  • Do you have any reason why you don't want to implement the JS fix for Internet explorer? There really aren't many other ways to go about this problem... – Wex Dec 09 '11 at 08:20
  • 1
    There is a good article about some css options you could consider at http://www.alistapart.com/articles/multicolumnlists/ . The article is fairly old but still relevant. Might help with IE solution. – Ben L Dec 09 '11 at 11:47
  • @TheUnshapedMan Are you allowed to use JS? or any classes as you like? – jQuerybeast Dec 09 '11 at 20:35

9 Answers9

36

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

Kevin Ji
  • 10,479
  • 4
  • 40
  • 63
sandeep
  • 91,313
  • 23
  • 137
  • 155
4

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>
Will Stern
  • 17,181
  • 5
  • 36
  • 22
4

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;
}
justisb
  • 7,081
  • 2
  • 26
  • 44
  • 1
    And here's a fully dynamic Javascript version, where I've included an "Add" button to insert another li element into the list. http://jsfiddle.net/swNYE/4/ – justisb Dec 09 '11 at 07:05
  • nice work. i like to add 1,2,3,4,5 vertically, but here that comes like 4 8 horizontally.. – anglimasS Dec 09 '11 at 08:49
  • I'm not sure what you mean exactly, do you mean set a minimum number of items in the first column? If so, you could do something like this. Just adjust the "iMin" variable in the "checkColumns" function. http://jsfiddle.net/swNYE/6/ – justisb Dec 09 '11 at 17:41
  • first set of ten numbers are aligning vertically in two rows , same way i want the next set of five numbers ie from 11 .... to be aligned vertically in parallel to the prev set of numbers. – anglimasS Dec 10 '11 at 05:07
  • Nice work that you have posted, but after complete the '10'. next number(11) should come in third row and 12 should come beneath 11 and so on. – anglimasS Dec 10 '11 at 05:08
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!

renevanderark
  • 975
  • 7
  • 15
  • 1
    Although I really enjoy reinventing the wheel, I would like to agree with @Marco Bax. There must be a good plugin for your purposes out there already; too bad I did not look for it before I started coding :) – renevanderark Dec 09 '11 at 15:59
3

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/

noob
  • 8,982
  • 4
  • 37
  • 65
2

SEE MY NEW ANSWER--MUCH BETTER THAN THIS

If you are dealing with fixed width items, then this pure css solution that works in IE7+. The example is http://jsfiddle.net/VVMnq/33/. This would require you to know some things about the html you are working with (where the new column is to start). Here is column 2 longer, just to see how it handles it: http://jsfiddle.net/VVMnq/42/

HTML

<ul class="TwoColumn">
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li class="column2">6</li>
    <li class="column2">7</li>
    <li class="column2">8</li>
    <li class="column2">9</li>
    <li class="column2">10</li>
</ul>

CSS

.TwoColumn {
    width: 20px;
    padding-left: 22px; /* width plus borders of li's */
}

.TwoColumn li {
    display: block;
    width: 100%;
    padding: 0;
    margin: 0 -22px 0 -22px; /* width of ul plus borders on li's */
    float: left;
    clear: left;
    border: 1px solid blue;
}

.TwoColumn .column2 {
    float: none; /* this could be set to float: left and it seemed to work also */
    clear: none;
    margin: 0 -11px 0 0; /* this should be half of margins for column 1 li's */
}
ScottS
  • 71,703
  • 13
  • 126
  • 146
  • sorry scott i want dynamically align(see my image) – anglimasS Dec 08 '11 at 13:36
  • I'm not sure what you mean. The image above is what I matched. It could be made dynamically with javascript (though if you want to do it dynamically, then I would just use javascript to reorder the elements and display it using the normal `float: left` technique). May I ask, are all these elements of equal size (like the image implies)? And are they in fact `li` elements all in one list? Is javascript an option? Is there a maximum number of elements/columns? – ScottS Dec 08 '11 at 18:35
  • @anglimass--See my new answer (separate post) that I believe fits your requirements now. – ScottS Dec 10 '11 at 22:44
1

The CSS:

ul.parent li {
  float: left;
}

Using jquery:

$('.parent>li:odd').css("clear", "both");

<ul class="parent">
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
  <li>6</li>
</ul>

Please take a look at http://api.jquery.com/even-selector/ and http://api.jquery.com/odd-selector/

Marco Bax
  • 383
  • 2
  • 6
1

NEW ANSWER that is totally different from the first. This assumes the height is always 5 high (which from comments on jblasco's solution made by anglimas, that is the requirement). The solution here is pure css (though if the number of elements is unknown, then some javascript would be required to "count" and set a class called first to indicate which element is in the first row).

The solution works in IE7+, and will accommodate any number of columns.

See http://jsfiddle.net/VVMnq/107/.

HTML

<ul class="MultiColumn">
    <li class="first">1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li class="first">6</li>
    <li>7</li>
    <li>8</li>
    <li>9</li>
    <li>10</li>
</ul>

CSS

.MultiColumn {
    overflow: auto;
    background-color: yellow;
    padding:0 10px 10px 0;
    float: left;
}

.MultiColumn li {
    display: block;
    width: 20px;
    height: 20px;
    padding: 0;
    margin: 10px 0px 10px 10px ;
    background-color: cyan;
    float: left;
}

.MultiColumn li.first {
    top: 0px;
}

.MultiColumn li.first + li  {
    margin: 40px 0 0 -20px;
}

.MultiColumn li.first + li + li {
    margin: 70px 0 0 -20px;
}

.MultiColumn li.first + li + li + li {
    margin: 100px 0 0 -20px;
}

.MultiColumn li.first + li + li + li + li {
    margin: 130px 0 0 -20px;
}
ScottS
  • 71,703
  • 13
  • 126
  • 146
  • @scott- I saw fiddle. You used class="first" don't use any class inside li because this is e-commerce purpose. Thanks a lot..... – anglimasS Dec 12 '11 at 05:09
  • @anglimass--You wanted IE7 or above, so you don't have a lot of choice. For that, you will need to use javascript somehow, and this allows you to just iterate through the elements and add the classname to the first and every fifth element and have the css do the rest of the work. Sandeep's answer is the best for modern browsers, but if you are trying to accommodate older (as you said), you don't have a lot of choice. I just hope with all the answers here you found the solution you needed. – ScottS Dec 12 '11 at 12:21
0

http://jsfiddle.net/rlemon/Y5ZvA/3/ ​ you can try this.. I haven't tested it with ie yet.

ul {
    width:60px; height: 60px;
}

ul li{
    float:left;
    width:20px;
    list-style:none;
}
ul, ul li {
    -moz-transform: rotate(-90deg) scaleX(-1);
    -o-transform: rotate(-90deg) scaleX(-1);
    -webkit-transform: rotate(-90deg) scaleX(-1);
    -ms-transform: rotate(-90deg) scaleX(-1);
    transform: rotate(-90deg) scaleX(-1);
   /* IE8+ - must be on one line, unfortunately */ 
   -ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=-3.061616997868383e-16, M12=1, M21=1, M22=3.061616997868383e-16, SizingMethod='auto expand')";

   /* IE6 and 7 */ 
   filter: progid:DXImageTransform.Microsoft.Matrix(
            M11=-3.061616997868383e-16,
            M12=1,
            M21=1,
            M22=3.061616997868383e-16,
            SizingMethod='auto expand');
}
​
rlemon
  • 17,518
  • 14
  • 92
  • 123