How to create a multi-column list?
Asked Answered
I

9

42

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.
Incidental answered 27/2, 2010 at 10:57 Comment(1)
There was an article on A List Apart a while back which covered exactly this question. I guess if what is mentioned there doesn't suffice you could of course always revert to server-sided coding or client-side coding to divide the list automatically in three portions.Addison
A
20

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

Applejack answered 27/2, 2010 at 11:43 Comment(2)
could you please provide working example using css3 column module.Progressionist
My problem with the css3 columns is they do not align to top very well. I ended up doing it with jquery: jsfiddle.net/EebVF/5 Using this jquery plugin: github.com/fzondlo/jquery-columnsMaxie
G
34

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.

Goodnatured answered 27/2, 2010 at 11:10 Comment(3)
is there anyway I can get them in vertical order using css/html? without having to break them up?Incidental
As far as I know, no. As mentioned, when css3 column mode will be supported it will be an easy task, but every trick I'm wondering needs to break-up the page in some way.Goodnatured
it seems to have an issue if for example, item 3 is 2 lines tall, and items 4 is 5 lines tall, etc, then there will be big gaps between item 1 and item 5, while the vertical arrangement can have always 1 empty line between item 1 and item 5Composure
A
20

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

Applejack answered 27/2, 2010 at 11:43 Comment(2)
could you please provide working example using css3 column module.Progressionist
My problem with the css3 columns is they do not align to top very well. I ended up doing it with jquery: jsfiddle.net/EebVF/5 Using this jquery plugin: github.com/fzondlo/jquery-columnsMaxie
F
5

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;
}
Fluoroscope answered 10/3, 2011 at 20:58 Comment(1)
This is a great solution, especially for a CMS where you might not want to hardcode the menu markup (to allow the end user to add more links to the menu later).Rig
P
3

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

Phytopathology answered 20/12, 2013 at 10:36 Comment(1)
Support is much wider nowadays[caniuse.com/#feat=multicolumn] and old browsers will still display the list. In fact you could combine this technique with this other one [https://mcmap.net/q/384373/-how-to-create-a-multi-column-list] for a nice fallback.Nessus
M
1

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!

Must answered 17/9, 2013 at 14:6 Comment(0)
D
0

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

Disorder answered 3/1, 2012 at 15:23 Comment(0)
I
0

For anyone looking for an updated answer, we can now use flexbox to make a vertical list with multiple columns.

HTML is as usual using <ol> and <li>.

In CSS,

ol {
    display: flex;
    flex-direction: column;
    flex-wrap: wrap;
    height: __px;
}

The height is key here, you want to set the height to make sure the list would wrap at appropriate points in your list. For example, if you have 100 items and want 5 columns, you want the height to fit 20 rows of items.

Additionally, you can also add the column-gap attribution to the CSS to adjust space between columns.

Incommode answered 19/4 at 8:25 Comment(0)
P
-1

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();
}
Phthisic answered 1/7, 2013 at 18:9 Comment(0)
L
-1

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.

Lemmons answered 25/8, 2017 at 11:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.