137

My webpage has a 'skinny' list: for example, a list of 100 items of one word in length each. To reduce scrolling, I want to present this list in two or even four columns on the page. How should I do this with CSS?

<ul>
    <li>Item</li>
    <li>Item</li>
    <li>Item</li>
    <li>Item</li>
    <li>Item</li>
    <li>Item</li>
    <li>Item</li>
    <li>Item</li>
    <li>Item</li>
    <li>Item</li>
</ul>

I prefer the solution to be flexible so that if the list grows to 200 items, I don't have to do a lot of manual adjustments to accommodate the new list.

TylerH
  • 19,065
  • 49
  • 65
  • 86
user776676
  • 3,985
  • 13
  • 53
  • 76
  • There is a library which does that - https://github.com/yairEO/listBreaker – vsync Oct 21 '16 at 14:22
  • I believe that CSS column option will do. This option is easy to use and change if there's a need. Here you have it explained in details -https://kolosek.com/css-columns/ – Nesha Zoric Feb 22 '18 at 12:24

9 Answers9

276

The CSS solution is: http://www.w3.org/TR/css3-multicol/

The browser support is exactly what you'd expect..

It works "everywhere" except Internet Explorer 9 or older: http://caniuse.com/multicolumn

ul {
    -moz-column-count: 4;
    -moz-column-gap: 20px;
    -webkit-column-count: 4;
    -webkit-column-gap: 20px;
    column-count: 4;
    column-gap: 20px;
}

See: http://jsfiddle.net/pdExf/

If IE support is required, you'll have to use JavaScript, for example:

http://welcome.totheinter.net/columnizer-jquery-plugin/

Another solution is to fallback to normal float: left for only IE. The order will be wrong, but at least it will look similar:

See: http://jsfiddle.net/NJ4Hw/

<!--[if lt IE 10]>
<style>
li {
    width: 25%;
    float: left
}
</style>
<![endif]-->

You could apply that fallback with Modernizr if you're already using it.

Woodrow Barlow
  • 6,567
  • 2
  • 33
  • 76
thirtydot
  • 210,355
  • 44
  • 377
  • 337
  • Is there a way to remove the top border on the first `li` in each column? – Yes Barry Aug 25 '14 at 21:49
  • 2
    This works great for a fixed space, but becomes an issue with responsive designs since the columns don't collapse like when using display:inline or inline-block. – unifiedac Feb 27 '15 at 20:29
  • 4
    Interesting fact: IE is the only major desktop browser to fully support this feature without prefixes (since IE10)... Oh, the irony... – NemoStein Apr 10 '15 at 05:25
  • Microsoft Edge is the only browser (on Windows) that display lists correctly, breaking between list items, not in the middle of a item. – NemoStein Aug 27 '15 at 12:15
  • Chrome is **highly** buggy with this method when the list items are more than simple texts. (multiline texts/ellipsis/absolute positioned element inside..many scenarios). Firefox is superb. as always. – vsync Sep 12 '16 at 11:40
  • 1
    It may be necessary for better cross browser support to include this additional property `list-style-position: inside;` which specifically addresses the problem pointed out by @vsync I believe. – ThisClark Jan 19 '17 at 15:33
  • please check this issue with your code http://jsfiddle.net/pdExf/ if the list is dynamic it may cause problem when number of list item becomes 1. – Prafulla Kumar Sahu Mar 23 '17 at 11:27
  • @PrafullaKumarSahu: I'm not sure what you mean. Can you make a demo showing the problem? You've just linked my original code there. Maybe setting `display: inline-block` on `ul` helps? – thirtydot Mar 23 '17 at 21:23
  • @thirtydot thank you so much for your kind reply,please check http://jsfiddle.net/pdExf/902/ the list contains only one item but displaying as multiple item . – Prafulla Kumar Sahu Mar 24 '17 at 01:59
  • 4
    @PrafullaKumarSahu: Try `li { break-inside: avoid; }`: http://jsfiddle.net/thirtydot/pdExf/903/. I'm not too familiar with CSS columns, so there might be a better way. – thirtydot Mar 24 '17 at 15:10
  • @thirtydot perfect :) I think you should edit your answer and include it, as it will improve the quality of the answer :) – Prafulla Kumar Sahu Mar 25 '17 at 18:25
  • @thirtydot why do we need so many properties? Why only `column-count` is not enough? – greatvovan Apr 06 '21 at 16:16
  • @greatvovan: This is a ten year old answer, you no longer need the [vendor prefixed](https://developer.mozilla.org/en-US/docs/Glossary/Vendor_Prefix) versions. They were needed in the past for multicolumn. – thirtydot Apr 06 '21 at 18:44
  • Terrible times... – greatvovan Apr 06 '21 at 22:30
19

If you are looking for a solution that works in IE as well, you could float the list elements to the left. However, this will result in a list that snakes around, like this:

item 1 | item 2 | item 3
item 4 | item 5

Instead of neat columns, like:

item 1 | item 4
item 2 | 
item 3 | 

The code to do that would be:

ul li {
  width:10em;
  float:left;
}

You could add a border-bottom to the lis to make the flow of the items from left to right more apparent.

Matt Hampel
  • 4,576
  • 10
  • 44
  • 76
  • while it might work for specific number of items, the result will not be pretty for just 2 items. – vsync Sep 12 '16 at 11:42
  • Another working CSS solution for the "neat columns": https://stackoverflow.com/q/54982323/1066234 – Avatar Aug 24 '19 at 17:20
13

If you want a preset number of columns, you can use column-count and column-gap, as mentioned above.

However, if you want a single column with limited height that would break into more columns if needed, this can be achieved quite simply by changing display to flex.

This will not work on IE9 and some other old browsers. You can check support on Can I use

<style>
  ul {
    display: -ms-flexbox;           /* IE 10 */
    display: -webkit-flex;          /* Safari 6.1+. iOS 7.1+ */
    display: flex;
    -webkit-flex-flow: wrap column; /* Safari 6.1+ */
    flex-flow: wrap column;
    max-height: 150px;              /* Limit height to whatever you need */
  }
</style>

<ul>
    <li>Item</li>
    <li>Item</li>
    <li>Item</li>
    <li>Item</li>
    <li>Item</li>
    <li>Item</li>
    <li>Item</li>
    <li>Item</li>
    <li>Item</li>
    <li>Item</li>
</ul>
Maciej Poleski
  • 131
  • 1
  • 2
  • 2
    Very close to what I'm going after. The only downside is that the width of the columns doesn't adapt to the content (try with different length items). Not sure how is the column-width defined. Maybe the with of the first element? In any case, any pointers on how to overcome this? – jorgeh Mar 09 '18 at 05:57
  • Would it be possible to cap the number of columns rather than the height? I need the items to fill into four columns, and the css `column-count` will do uneven number of rows within the columns. Like 6 items in the first column, then 4, then 6, then 5. – Virge Assault Aug 27 '19 at 16:54
  • Would be nice if you label the items eg "Item 1", "Item 2" so that viewers can see the flow of the elements – allkenang Apr 07 '20 at 01:53
11

2021 - keep it simple, use CSS Grid

Lots of these answers are outdated, it's 2021 and we shouldn't be enabling people who are still using IE9. It's way more simple to just use CSS grid.

The code is very simple, and you can easily adjust how many columns there are using the grid-template-columns. See this and then play around with this fiddle to fit your needs.

.grid-list {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
}
<ul class="grid-list">
  <li>item</li>
  <li>item</li>
  <li>item</li>
  <li>item</li>
  <li>item</li>
  <li>item</li>
  <li>item</li>
  <li>item</li>
  <li>item</li>
  <li>item</li>
  <li>item</li>
  <li>item</li>
</ul>
maxshuty
  • 4,793
  • 7
  • 41
  • 55
3

This answer doesn't necessarily scale but only requires minor adjustments as the list grows. Semantically it might seem a little counter-intuitive since it is two lists, but aside from that it'll look the way you want in any browser ever made.

ul {
  float: left;
}

ul > li {
  width: 6em;
}
<!-- Column 1 -->
<ul>
  <li>Item 1</li>
  <li>Item 2</li>
  <li>Item 3</li>
</ul>
<!-- Column 2 -->
<ul>
  <li>Item 4</li>
  <li>Item 5</li>
  <li>Item 6</li>
</ul>
Alan Hape
  • 61
  • 2
  • 1
    _Note:_ this answer will reduce the accessibility of your website for users using screen readers, etc. – maxshuty Nov 28 '20 at 00:50
1

I've found that (currently) Chrome (Version 52.0.2743.116 m) has tons of quirks and issues with css column-count regarding overflow items and absolute positioned elements inside items, especially with some dimensions transitions..

it's a total mess and cannot be fix, so I tried tackling this through simple javascript, and had created a library which does that - https://github.com/yairEO/listBreaker

Demo page

vsync
  • 87,559
  • 45
  • 247
  • 317
  • I prefer the jQuery columnizer plugin, in my opinion it had better functionality for what I was doing (was able to sort alphabetically, descending or ascending, columns count, columns width & more). [jQuery Columnizer - WelcomeToTheInter.Net](http://welcome.totheinter.net/columnizer-jquery-plugin/) – brandito Oct 23 '17 at 05:51
  • @Brandito - well, the Columnizer code sure has more options, since it's almost a 1,000 lines of code, compared to mine which is about a 120 lines.. but does the job well – vsync Oct 23 '17 at 07:37
  • yes but my problem needed the list to stay as one list, what is more useful / needed depends on the use case. – brandito Oct 23 '17 at 23:23
0

If you can support it CSS Grid is probably the cleanest way for making a one-dimensional list into a two column layout with responsive interiors.

ul {
  max-width: 400px;
  display: grid;
  grid-template-columns: 50% 50%;
  padding-left: 0;
  border: 1px solid blue;
}

li {
  list-style: inside;
  border: 1px dashed red;
  padding: 10px;
}
<ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
  <li>6</li>
  <li>7</li>
  <li>8</li>
  <li>9</li>
<ul>

These are the two key lines which will give you your 2 column layout

display: grid;
grid-template-columns: 50% 50%;
mattLummus
  • 496
  • 3
  • 11
  • This is not responsive, when I use five column, it is not showing correctly in handheld devices. – Patzu Oct 27 '20 at 21:12
0

The mobile-first way is to use CSS Columns to create an experience for smaller screens then use Media Queries to increase the number of columns at each of your layout's defined breakpoints.

ul {
  column-count: 2;
  column-gap: 2rem;
}
@media screen and (min-width: 768px)) {
  ul {
    column-count: 3;
    column-gap: 5rem;
  }
}
<ul>
  <li>Item</li>
  <li>Item</li>
  <li>Item</li>
  <li>Item</li>
  <li>Item</li>
  <li>Item</li>
  <li>Item</li>
  <li>Item</li>
  <li>Item</li>
  <li>Item</li>
</ul>
Josh Habdas
  • 6,370
  • 2
  • 53
  • 55
0

Here is what I did

ul {
      display: block;
      width: 100%;
}

ul li{
    display: block;
    min-width: calc(30% - 10px);
    float: left;
}

ul li:nth-child(2n + 1){
    clear: left;
}
<ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
  <li>6</li>
  <li>7</li>
  <li>8</li>
  <li>9</li>
  <li>0</li>
</ul>
GuruKay
  • 3,130
  • 2
  • 18
  • 8