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.

Solution 1

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.

Solution 2

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.

Solution 3

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: flex;
    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>

Solution 4

It's 2022 - keep it simple, use CSS grid or column-count

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 or column-count.

The code is very simple, and you can easily adjust how many columns there are using grid-template-columns or column-count.

grid solution:

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

column-count solution that maintains order:

.column-list {
  column-count: 4;
}
<ul class="column-list">
  <li>item 1</li>
  <li>item 2</li>
  <li>item 3</li>
  <li>item 4</li>
  <li>item 5</li>
  <li>item 6</li>
  <li>item 7</li>
  <li>item 8</li>
  <li>item 9</li>
  <li>item 10</li>
  <li>item 11</li>
  <li>item 12</li>
</ul>

Solution 5

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>

Solution 6

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>

Solution 7

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

Solution 8

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

Solution 9

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>