开发者

How to create a multi-column list?

I have an "Ordered List" which contains about 100 "List Items". This ol makes my page very long and users have to scroll too much.

How can I get the UL to show like this:

1.           6.           11.
2.           7.     开发者_开发知识库      12.
3.           8.           13.
4.           9.           14.
5.          10.           15.


If for you don't care about the vertical order, but only the layout:

1.      2.      3.       4.
5.      6.      7.       8.
9.      10.     11.      12.

You can simply set the li elements this way:

li {
    display: block;
    width: 25%;
    float: left;
}

It should work. If you need to have them in vertical order you need to act in the php script dividing them into separate divs and then float them.


You could use the CSS multi-column layout module. You can check support at Caniuse.


I was able to get the proper ordering with a little jQuery:

function splitList($list, n) {
    var i, k;
    var colHeight = Math.ceil($list.children().length / n)
    var colWidth = Math.floor(100 / n) + "%"

    for (i = 0; i < n; i++) {
        $list.append("<ul class='liCol'></ul>")
        for (k = 0; k < colHeight; k++) {
            $list.children("li").eq(0).appendTo(".liCol:last")          
        }   
    }

    $(".liCol").css("width", colWidth)
    $list.show() // list originally hidden to avoid displaying before ready
}

basic styles for .liCol:

.liCol {
    padding: 0px;
    margin: 0px;
    float: left;
}


If you use CSS multi-column layout, you can do it this way:

ul {
    list-style-type: none;
    counter-reset: section;
    -moz-column-count: 3;
    -moz-column-gap: 20px;
    -webkit-column-count: 3;
    -webkit-column-gap: 20px;
    column-count: 3;
    column-gap: 20px;
}

ul li {
    padding-left: 30px;
    position: relative;
}

ul li:before {
    counter-increment: section;
    content: counter(section) ".";
    margin: 0 0 0 -34px;
    text-align: right;
    width: 2em;
    display: inline-block;
    position: absolute;
    height: 100%;
}
<ul>
    <li>List item</li>
    <li>List item</li>
    <li>List item</li>
    <li>List item</li>
    <li>List item</li>
    <li>List item</li>
    <li>List item</li>
    <li>List item</li>
    <li>List item</li>
    <li>List item</li>
    <li>List item</li>
    <li>List item</li>
    <li>List item</li>
    <li>List item</li>
    <li>List item</li>
    <li>List item</li>
    <li>List item</li>
    <li>List item</li>
    <li>List item</li>
</ul>

JSFiddle demo


I created a solution that also works for ordered (numbered) lists. These lists have to continue numbering through the columns.

Add the following script to your page (doesn't matter where, nicest is in a seperate js-file):

<script type="text/javascript">
// As soon as the document's structure has been loaded:
document.addEventListener( "DOMContentLoaded", function() {
    // For each html elem:
    elems = document.getElementsByTagName("*"); // OL and UL wanted: chose all (*) here and select later.
    for ( var e = 0; e < elems.length; e++ ) {
        // Check if elem is a list (ordered/unordered) and has class name "cols":
        if ( ( elems[e].tagName == "OL" || elems[e].tagName == "UL" ) && elems[e].className.search("cols") > -1 ) {
            // Collect list items and number of columns (from the rel attribute):
            var list = elems[e];
            var listItems = list.getElementsByTagName("LI");
            var Ncols = list.getAttribute("rel")*1; // *1 converts rel from string to int.
            // Determine total number of items, items per column and column width:
            var Ntotal = listItems.length;
            var Npercol = Math.ceil( Ntotal/Ncols );
            var colWidth = Math.floor( 100/Ncols )+"%";
            // For each column:
            for ( var c = 0; c < Ncols; c++ ) {
                // Create column div:
                var colDiv = document.createElement("DIV");
                colDiv.style.cssFloat = "left";
                colDiv.style.width = colWidth;
                // Add list items to column div:
                var i_start = c*Npercol;
                var i_end = Math.min( (c+1)*Npercol, Ntotal );
                for ( var i = i_start; i < i_end; i++ )
                    colDiv.appendChild( listItems[0] ); // Using listItems[0] instead of listItems[i], because items are moved to colDiv!
                // Add column div to list:  
                list.appendChild( colDiv );
            }
        }
    }
} );
</script>

Then you can simply create multiple columns lists like this:

<ol class="cols" rel="3">
    <li>A</li>
    <li>B</li>
    <li>C</li>
    <li>D</li>
    <li>E</li>
    <li>F</li>
    <li>G</li>
</ol>

So, setting class="cols" and rel="[number_of_columns]" and the script will do the rest!


You can use 2D transforms: they have a wider support by modern browser than CSS3 columns. See my answer here

2 row element layout within horizontal div


Since I had the same problem and couldn't find anything "clean" I thought I'd posted my solution. In this example I use a reversed while loop so I can use splice instead of slice. The advantage now is splice() only needs an index and a range where slice() needs an index and the total. The latter tends to become difficult while looping.

Disadvantage is I need to reverse the stack while appending.

Example:

cols = 4; liCount = 35

for loop with slice = [0, 9]; [9, 18]; [18, 27]; [27, 35]

reversed while with splice = [27, 8]; [18, 9]; [9, 9]; [0, 9]

Code:

// @param (list): a jquery ul object
// @param (cols): amount of requested columns
function multiColumn (list, cols) {
    var children = list.children(),
        target = list.parent(),
        liCount = children.length,
        newUl = $("<ul />").addClass(list.prop("class")),
        newItems,
        avg = Math.floor(liCount / cols),
        rest = liCount % cols,
        take,
        stack = [];

    while (cols--) {
        take = rest > cols ? (avg + 1) : avg;
        liCount -= take;

        newItems = children.splice(liCount, take);
        stack.push(newUl.clone().append(newItems));
    }

    target.append(stack.reverse());
    list.remove();
}


So I've looked into this and found a solution that will work for all browsers.

My HTML list:

<ol class="list-items">
    <li>Item1</li>
    <li>Item2</li>
    <li>Item3</li>
    <li>Item4</li>
    <li class="second-list">Item5</li>
    <li class="second-list">Item6</li>
    <li class="second-list">Item7</li>
    <li class="second-list">Item8</li>
</ol>

Notice I gave the last 4 list items a class of second-list, this is important for our jQuery.

Next, on my webpage, I made a div with class second-list-appender in the second column, the column I want my second list to be in.

var secondListStart = $(".list-items").children().length - 3;

$(".second-list-appender").append($("<ol start=" + secondListStart + ">"));
$(".second-list-appender ol").append($(".second-list"));
$(".second-list-appender").append($("</ol>"));

See, I actually make 2 lists out of 1, but make it look like one list in 2 columns, by giving start of the second list the next number of the previous list.

I did it with 2 columns, but you can just repeat this process, or create a function and call that within a loop for how many times you want to repeat it.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜