306

With the following HTML, what is the easiest method to display the list as two columns?

<ul>
    <li>A</li>
    <li>B</li>
    <li>C</li>
    <li>D</li>
    <li>E</li>
</ul>

Desired display:

A B
C D
E

The solution needs to work with Internet Explorer.

atp03
  • 3,539
  • 3
  • 17
  • 20
  • 1
    Here's a live example of how to easily do it in jquery: jsfiddle.net/EebVF/5 Using this jquery plugin: github.com/fzondlo/jquery-columns - I like this better than with CSS because with the CSS solution not everything aligns vertically to the top. – newUserNameHere May 03 '14 at 14:25

19 Answers19

531

Modern Browsers

leverage the css3 columns module to support what you are looking for.

http://www.w3schools.com/cssref/css3_pr_columns.asp

CSS:

ul {
  columns: 2;
  -webkit-columns: 2;
  -moz-columns: 2;
}

http://jsfiddle.net/HP85j/8/

Legacy Browsers

Unfortunately for IE support you will need a code solution that involves JavaScript and dom manipulation. This means that anytime the contents of the list changes you will need to perform the operation for reordering the list into columns and reprinting. The solution below uses jQuery for brevity.

http://jsfiddle.net/HP85j/19/

HTML:

<div>
    <ul class="columns" data-columns="2">
        <li>A</li>
        <li>B</li>
        <li>C</li>
        <li>D</li>
        <li>E</li>
        <li>F</li>
        <li>G</li>
    </ul>
</div>

JavaScript:

(function($){
    var initialContainer = $('.columns'),
        columnItems = $('.columns li'),
        columns = null,
        column = 1; // account for initial column
    function updateColumns(){
        column = 0;
        columnItems.each(function(idx, el){
            if (idx !== 0 && idx > (columnItems.length / columns.length) + (column * idx)){
                column += 1;
            }
            $(columns.get(column)).append(el);
        });
    }
    function setupColumns(){
        columnItems.detach();
        while (column++ < initialContainer.data('columns')){
            initialContainer.clone().insertBefore(initialContainer);
            column++;
        }
        columns = $('.columns');
    }

    $(function(){
        setupColumns();
        updateColumns();
    });
})(jQuery);

CSS:

.columns{
    float: left;
    position: relative;
    margin-right: 20px;
}

EDIT:

As pointed out below this will order the columns as follows:

A  E
B  F
C  G
D

while the OP asked for a variant matching the following:

A  B
C  D
E  F
G

To accomplish the variant you simply change the code to the following:

function updateColumns(){
    column = 0;
    columnItems.each(function(idx, el){
        if (column > columns.length){
            column = 0;
        }
        $(columns.get(column)).append(el);
        column += 1;
    });
}
Gabriel
  • 18,322
  • 2
  • 37
  • 44
  • 4
    You're not displaying the items in the correct order: http://jsfiddle.net/HP85j/258/ For example, the desired display in the first line is `A B` (the second element should be appended on the right), but in your examples is `A E`. – Paolo Moretti Feb 25 '14 at 12:10
  • 1
    Great work, although the logic is flawed if there are more than 2 columns, I've created the fix here: http://jsfiddle.net/HP85j/393/ – Tr1stan May 23 '14 at 08:18
  • 2
    the bullets are missing – Jaider Jun 12 '14 at 15:30
  • interestingly, this doesn't print. :\ ... also you need to re-add list-style. At least in Chrome. – Ben Lesh Sep 30 '14 at 05:40
  • 1
    It's probably more likely to want the list to fill down column 1 before column 2. It might be easier to simply reorder the items of the list so it appears that they filled across before down. Of course that may require redoing if the list changes. Anyway, Gabriel's CSS answer was just what I needed, thank you! – punstress Mar 10 '15 at 17:44
  • 3
    Just a late update, I believe the first option will now work in modern IE browsers. – Fizz Jun 25 '15 at 22:32
  • How do you prevent items from cutting off in the middle when they roll over to the next column? [Like this](http://i.imgur.com/I7Jx08L.png) – RocketGuy3 Aug 20 '15 at 00:07
  • 1
    Nevermind, found it: http://stackoverflow.com/questions/3322891/why-is-chrome-cutting-off-text-in-my-css3-multi-column-layout – RocketGuy3 Aug 20 '15 at 20:39
  • Legacy means for columns below IE10: https://caniuse.com/#feat=multicolumn So hopefully nowadays nobody has to build html working is such old browsers – sschoof Aug 29 '17 at 13:08
  • Doesn't display bullets on the second column – Russell Strauss Jul 02 '18 at 21:30
  • The comments mentionning the order is not the one requested in the question are not relevant. OP chose to use a
      element, the order shouldn't be important...
    – Laurent S. Jan 18 '20 at 09:07
  • Worked for me in chrome and firefox. – Divyani Singh Aug 03 '20 at 07:34
101

I was looking at @jaider's solution which worked but I'm offering a slightly different approach that I think is more easy to work with and which I've seen to be good across browsers.

ul{
    list-style-type: disc;
    -webkit-columns: 2;
    -moz-columns: 2;
    columns: 2;
    list-style-position: inside;//this is important addition
}

By default un-ordered list display the bullet position outside but then in some browsers it would cause some display problems based on the browser's way of laying out your website.

To get it to display in the format:

A B
C D
E

etc. use the following:

ul li{
    float: left;
    width: 50%;//helps to determine number of columns, for instance 33.3% displays 3 columns
}
ul{
    list-style-type: disc;
}

This should solve all your problems with displaying columns. All the best and thanks @jaider as your response helped to guide me to discover this.

Cœur
  • 37,241
  • 25
  • 195
  • 267
Winnifred
  • 1,202
  • 1
  • 8
  • 10
  • 5
    There is a problem with this method. It works great for displaying very short (1 character in this example) list items. Create a list with longer descriptions and the second column overlaps the first, as well as runs out of the ul container. – Shaggy Aug 19 '15 at 16:01
  • 2
    I tweaked this slightly by changing float: left to display: inline-block for li elements, other than that this worked wonders for me. – ZeRemz Jun 23 '20 at 15:36
47

I tried posting this as a comment, but couldn't get the columns to display right (as per your question).

You are asking for:

A B

C D

E

... but the answer accepted as the solution will return:

A D

B E

C

... so either the answer is incorrect or the question is.

A very simple solution would be to set the width of your <ul> and then float and set the width of your <li> items like so

<ul>
    <li>A</li>
    <li>B</li>
    <li>C</li>
    <li>D</li>
    <li>E</li>
</ul>

ul{
    width:210px;
}
li{
    background:green;
    float:left;
    height:100px;
    margin:0 10px 10px 0;
    width:100px;
}
li:nth-child(even){
    margin-right:0;
}

Example here http://jsfiddle.net/Jayx/Qbz9S/1/

If your question is wrong, then the previous answers apply (with a JS fix for lacking IE support).

Jayx
  • 3,896
  • 3
  • 27
  • 37
  • @Gabriel your solution and the behavior is good and as expected, so I'm not trying to knock your answer hey ... I just think that the question might have been misinterpreted ... either way - the question has been answered no matter which is the correct question :D – Jayx Feb 08 '13 at 09:22
22

Now days, for the expected result, display:grid; would do (be the easiest ?):

ul {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
}
<ul>
  <li>A</li>
  <li>B</li>
  <li>C</li>
  <li>D</li>
  <li>E</li>
</ul>

you can also get the columns shrinking on the left and able to have different width:

ul {
  display: grid;
  grid-template-columns: repeat(2, auto);
  justify-content: start;
}

li {
  margin-left: 1em;
  border: solid 1px;/*see me */
}
<ul>
  <li>A</li>
  <li>B</li>
  <li>C 123456</li>
  <li>D</li>
  <li>E</li>
</ul>
G-Cyrillus
  • 101,410
  • 14
  • 105
  • 129
  • 1
    Thanks! This served me better than the accepted answer cause it makes the elements in the columns match in height – tbotalla Apr 25 '22 at 03:25
  • Is there a way to make it display alphabetically from top to bottom instead of left to right? – Dex Nov 08 '22 at 07:02
  • @Dex With grid ? Yes, but you need to define either an height or a numbers of row , here 3 rows would do : https://codepen.io/gc-nomade/pen/gOKgONa – G-Cyrillus Nov 08 '22 at 19:16
20

I like the solution for modern browsers, but the bullets are missing, so I add it a little trick:

http://jsfiddle.net/HP85j/419/

ul {
    list-style-type: none;
    columns: 2;
    -webkit-columns: 2;
    -moz-columns: 2;
}


li:before {
  content: "• ";
}

enter image description here

Jaider
  • 14,268
  • 5
  • 75
  • 82
  • Here we can change the color of the items without change the color of the bullet http://jsfiddle.net/HP85j/444/ – Jaider Jul 07 '14 at 22:47
  • 3
    I think `list-style-position: inside;` is a better solution for the bullets to show up properly. – Alexis Wilke Feb 22 '16 at 05:51
15

Here's a possible solution:

Snippet:

ul {
  width: 760px;
  margin-bottom: 20px;
  overflow: hidden;
  border-top: 1px solid #ccc;
}
li {
  line-height: 1.5em;
  border-bottom: 1px solid #ccc;
  float: left;
  display: inline;
}
#double li {
  width: 50%;
}
<ul id="double">
  <li>first</li>
  <li>second</li>
  <li>third</li>
  <li>fourth</li>
</ul>

And it is done.
For 3 columns use li width as 33%, for 4 columns use 25% and so on.

Ani Menon
  • 27,209
  • 16
  • 105
  • 126
Abdul
  • 3,739
  • 1
  • 12
  • 5
7

This is the simplest way to do it. CSS only.

  1. add width to the ul element.
  2. add display:inline-block and width of the new column (should be less than half of the ul width).
ul.list {
  width: 300px;  
}

ul.list li{
  display:inline-block;
  width: 100px;
}
<ul class="list">
    <li>A</li>
    <li>B</li>
    <li>C</li>
    <li>D</li>
    <li>E</li>
</ul>
Aviv Shaal
  • 71
  • 1
  • 2
6

This can be achieved using column-count css property on parent div,

like

 column-count:2;

check this out for more details.

How to make floating DIV list appear in columns, not rows

Community
  • 1
  • 1
maximus ツ
  • 7,949
  • 3
  • 25
  • 54
  • 1
    `column-count` will not display the items in the correct order. For example, the desired display in the first line is `A B` (the second element should be appended on the right), but if you use `column-count` it will be `A E`. – Paolo Moretti Feb 25 '14 at 12:14
6

You can use CSS only to set two columns or more

A E

B

C

D

 <ul class="columns">
    <li>A</li>
    <li>B</li>
    <li>C</li>
    <li>D</li>
    <li>E</li>
</ul>

ul.columns  {
   -webkit-columns: 60px 2;
   -moz-columns: 60px 2;
    columns: 60px 2;
   -moz-column-fill: auto;
   column-fill: auto;
 }
Bouhejba zied
  • 61
  • 1
  • 4
4

Assuming that a multi-column layout may work well with a centered layout, justify a grid layout with a horizontal gap.

p {
  text-align: justify;
}

ul {
  display: grid;
  grid-template-columns: repeat(3, auto);
  justify-content: space-around;
  gap: 0 3em;
  text-transform: capitalize;
}
<p>In publishing and graphic design, Lorem ipsum is a placeholder text commonly used to demonstrate the visual form of a document or a typeface without relying on meaningful content. Lorem ipsum may be used as a placeholder before final copy is available.</p>
<ul>
  <li>one</li>
  <li>two</li>
  <li>three</li>
  <li>four</li>
  <li>five</li>
  <li>six</li>
  <li>seven</li>
  <li>eight</li>
  <li>nine</li>
  <li>ten</li>
</ul>
<p>In publishing and graphic design, Lorem ipsum is a placeholder text commonly used to demonstrate the visual form of a document or a typeface without relying on meaningful content. Lorem ipsum may be used as a placeholder before final copy is available.</p>
OXiGEN
  • 2,041
  • 25
  • 19
2

You can do this really easily with the jQuery-Columns Plugin for example to split a ul with a class of .mylist you would do

$('.mylist').cols(2);

Here's a live example on jsfiddle

I like this better than with CSS because with the CSS solution not everything aligns vertically to the top.

newUserNameHere
  • 17,348
  • 18
  • 49
  • 79
  • Interesting, but it actually breaks down the `
      ` list in multiple lists... That could complicate other things.
    – Alexis Wilke Feb 22 '16 at 05:56
  • This was actually the solution i was after thanks, to the downvoter this answer is valid if you read the OP's question and there was no need to DV. – Tricky May 24 '16 at 08:59
2

more one answer after a few years!

in this article: http://csswizardry.com/2010/02/mutiple-column-lists-using-one-ul/

HTML:

<ul id="double"> <!-- Alter ID accordingly -->
  <li>CSS</li>
  <li>XHTML</li>
  <li>Semantics</li>
  <li>Accessibility</li>
  <li>Usability</li>
  <li>Web Standards</li>
  <li>PHP</li>
  <li>Typography</li>
  <li>Grids</li>
  <li>CSS3</li>
  <li>HTML5</li>
  <li>UI</li>
</ul>

CSS:

ul{
  width:760px;
  margin-bottom:20px;
  overflow:hidden;
  border-top:1px solid #ccc;
}
li{
  line-height:1.5em;
  border-bottom:1px solid #ccc;
  float:left;
  display:inline;
}
#double li  { width:50%;}
#triple li  { width:33.333%; }
#quad li    { width:25%; }
#six li     { width:16.666%; }
user3632930
  • 311
  • 2
  • 8
1

In updateColumns() need if (column >= columns.length) rather than if (column > columns.length) to list all elements (C is skipped for example) so:

function updateColumns(){
    column = 0;
    columnItems.each(function(idx, el){
        if (column >= columns.length){
            column = 0;
        }
        console.log(column, el, idx);
        $(columns.get(column)).append(el);
        column += 1;
    });
}

http://jsfiddle.net/e2vH9/1/

Bonifacio2
  • 3,405
  • 6
  • 34
  • 54
Daver
  • 23
  • 5
1

With Bootstrap... This answer (https://stackoverflow.com/a/23005046/1128742) got me pointed towards this solution:

<ul class="list-unstyled row">
   <li class="col-xs-6">Item 1</li>
   <li class="col-xs-6">Item 2</li>
   <li class="col-xs-6">Item 3</li>
</ul>

http://jsfiddle.net/patrickbad767/472r0ynf/

Community
  • 1
  • 1
patrickbadley
  • 2,510
  • 2
  • 29
  • 30
1

The legacy solution in the top answer didn't work for me because I wanted to affect multiple lists on the page and the answer assumes a single list plus it uses a fair bit of global state. In this case I wanted to alter every list inside a <section class="list-content">:

const columns = 2;
$("section.list-content").each(function (index, element) {
    let section = $(element);
    let items = section.find("ul li").detach();
    section.find("ul").detach();
    for (let i = 0; i < columns; i++) {
        section.append("<ul></ul>");
    }
    let lists = section.find("ul");
    for (let i = 0; i < items.length; i++) {
        lists.get(i % columns).append(items[i]);
    }
});
Tom
  • 22,301
  • 5
  • 63
  • 96
  • how is it possible for instance generate two columns, one just contains the tile and the other an unordered list? – Dalek Jun 09 '17 at 16:37
  • Not quite sure what you mean. If you have a series of items with titles, you could put them in a single list going title, item, title, item and then this should work for you. – Tom Jun 09 '17 at 16:45
1

This worked for me. is the best solution because the cells in a row have the same height without taking care of the content

ul {
  display: grid;
  grid-template-columns: repeat(2, 1fr); 
  list-style-position: inside;
  list-style-type: none;
}
li {  border: solid 1px; }
<ul>
  <li>asdasd asdad asdasd asdasd adasdasdasd adasdadadada adadas dasdadasdasd asd aA</li>
  <li>B</li>
  <li>C</li>
  <li>D</li>
  <li>E</li>
</ul>
Fabiel León
  • 111
  • 1
  • 5
0

Though I found Gabriel answer to work to a degree i did find the following when trying to order the list vertically (first ul A-D and second ul E-G):

  • When the ul had an even number of li's in it, it was not evenly spreading it across the ul's
  • using the data-column in the ul didn't seem to work very well, I had to put 4 for 3 columns and even then it was still only spreading the li's into 2 of the ul generated by the JS

I have revised the JQuery so the above hopefully doesn't happen.

(function ($) {
    var initialContainer = $('.customcolumns'),
        columnItems = $('.customcolumns li'),
        columns = null,
        column = 0;
    function updateColumns() {
        column = 0;
        columnItems.each(function (idx, el) {
            if ($(columns.get(column)).find('li').length >= (columnItems.length / initialContainer.data('columns'))) {
                column += 1;
            }
            $(columns.get(column)).append(el);
        });
    }
    function setupColumns() {
        columnItems.detach();
        while (column++ < initialContainer.data('columns')) {
            initialContainer.clone().insertBefore(initialContainer);
            column++;
        }
        columns = $('.customcolumns');
        updateColumns();
    }

    $(setupColumns);
})(jQuery);
.customcolumns {
  float: left;
  position: relative;
  margin-right: 20px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
  <ul class="customcolumns" data-columns="3">
    <li>A</li>
    <li>B</li>
    <li>C</li>
    <li>D</li>
    <li>E</li>
    <li>F</li>
    <li>G</li>
    <li>H</li>
    <li>I</li>
    <li>J</li>
    <li>K</li>
    <li>L</li>
    <li>M</li>
  </ul>
</div>
0

Here is an easy way to make a multiple column list using nothing more than simple CSS. The style tags can obviously be put into a CSS if desired.

<p>Materials List</p>
<ul style="display: inline-block; float: left">
    <u>Item Description<u>
    <li>1/2" x 4' wood dowel</li>
    <li>1/2" x 12"  PVC pipe</li>
    <li>1/2" PVC pipe end cap</li>
    <li>7/16" x 3" light duty expansion spring</li>
    <li>6" plastic zip ties</li>
    <li>Light weight antenna</li>
</ul>
<div style="display: inline-block; margin-left: 1em">
    <u>Qty</u>
    <div style="text-indent: 0.5em">3</div>
    <div style="text-indent: 0.5em">1</div>
    <div style="text-indent: 0.5em">1</div>
    <div style="text-indent: 0.5em">2</div>
    <div style="text-indent: 0.5em">8</div>
    <div style="text-indent: 0.5em">1</div>
</div>
<p></p>
NOYB
  • 625
  • 8
  • 14
-1

Thisd was a perfect solution for me, looking it for years:

http://css-tricks.com/forums/topic/two-column-unordered-list/

rok
  • 47
  • 6
  • 3
    _"Always quote the most relevant part of an important link, in case the target site is unreachable or goes permanently offline"_ - http://stackoverflow.com/help/how-to-answer – Sk8erPeter Jan 03 '15 at 01:46
  • No need -- it is the link/reference for the code used by `Abdul` in his answer, identical to even the width and ID used. – cssyphus Oct 01 '15 at 01:34