如何创建多列列表?

41

我有一个包含100个“列表项”的“有序列表”。这个ol使得我的页面非常长,用户需要滚动很多。

我该如何使UL显示如下:

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

有一篇关于这个问题的文章在《A List Apart》上,你可以去看看(http://www.alistapart.com/articles/multicolumnlists/)。如果那里提到的不够用,你当然可以使用服务器端编程或客户端编程来自动将列表分成三部分。 - Michiel
8个回答

33
如果您不在意垂直顺序,只关心布局:
1.      2.      3.       4.
5.      6.      7.       8.
9.      10.     11.      12.

您可以通过以下方式设置li元素:

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

它应该能够工作。如果你需要按垂直顺序排列它们,则需要在 PHP 脚本中将它们分成单独的 div,并使用浮动(float)将它们排列。


有没有办法使用CSS/HTML将它们垂直排列?而无需将它们分开? - anonymous
1
据我所知,不行。正如提到的那样,当支持css3列模式时,这将是一项容易的任务,但我想到的每个技巧都需要以某种方式分割页面。 - Enrico Carlesso
1
如果例如,项目3有2行高度,而项目4有5行高度等,则项目1和项目5之间将会有很大的间隙问题,而垂直排列始终可以在项目1和项目5之间保持1个空行。 - nonopolarity

20

1
请您提供一个使用CSS3列模块的工作示例,谢谢。 - Santosh
我的问题是CSS3列不太好地对齐到顶部。最终我用jQuery解决了它:http://jsfiddle.net/EebVF/5 使用这个jQuery插件:http://github.com/fzondlo/jquery-columns - newUserNameHere

5
我使用了一点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
}
  • .liCol的基本样式:
  • .liCol {
        padding: 0px;
        margin: 0px;
        float: left;
    }
    

    这是一个很好的解决方案,特别适用于 CMS,您可能不希望硬编码菜单标记(以允许最终用户稍后添加更多链接到菜单)。 - deweydb

    3
    如果您使用CSS多列布局,可以这样做:

    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演示


    现在的支持范围更广了[http://caniuse.com/#feat=multicolumn],旧浏览器仍然可以显示列表。实际上,您可以将此技术与此其他技术[https://dev59.com/WHE95IYBdhLWcg3wWMlQ#2347094]结合使用,以获得良好的回退效果。 - Oriol

    1
    我创建了一个解决方案,也适用于有序(编号)列表。这些列表必须通过列继续编号。
    将以下脚本添加到您的页面中(位置无关紧要,最好是在单独的js文件中):
    <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>
    

    然后,您可以像这样创建多列列表:
    <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>
    

    因此,设置 class="cols" 和 rel="[number_of_columns]",脚本将完成其余工作!


    0

    -1

    我已经研究了这个问题,并找到了一个适用于所有浏览器的解决方案。

    我的HTML列表:

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

    注意,我给最后4个列表项添加了一个名为second-list的类,这对我们的jQuery很重要。

    接下来,在我的网页上,我在第二列中创建了一个带有second-list-appender类的div,这是我想要放置第二个列表的列。

    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>"));
    

    看,我实际上是从一个列表中生成了两个列表,但通过在第二个列表的起始处使用前一个列表的下一个数字,让它看起来像一个有两列的列表。

    我用两列实现了它,但你也可以重复这个过程,或创建一个函数,并在循环内调用该函数,以重复多少次都可以。


    -1

    由于我遇到了同样的问题,找不到任何“干净”的解决方案,所以我想发布我的解决方案。在这个例子中,我使用了一个反向的while循环,这样我就可以使用splice而不是slice。现在的优点是splice()只需要一个索引和一个范围,而slice()需要一个索引和总数。后者在循环时往往变得困难。

    缺点是我需要在附加时反转堆栈。

    示例:

    cols = 4; liCount = 35

    使用slice的for循环= [0, 9]; [9, 18]; [18, 27]; [27, 35]

    使用splice的反向while = [27, 8]; [18, 9]; [9, 9]; [0, 9]

    代码:

    // @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();
    }
    

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接