64

I am building a menu system presented to the user in multi-column format. The column-count property in CSS3 gets me 90% of the way there, but I'm having difficulties with alignment under Chrome.

The menu is relatively simple:

  • an unordered list divided into multiple-columns by the column-count property
  • columns should fill sequentially, so column-fill: auto
  • menu items are represented as list items
  • each list item has a a clickable anchor tag, extended fully via display: block

The alignment issue I'm having is most noticeable with a top-border and some background coloring on each list item. In Firefox, the list items are always aligned cleanly across each column, never bleeding into the previous/next column. In Chrome, alignment is a crapshoot, varying with how many list items are present and any padding/margin properties.

I've posted the code for a simple test case here: http://pastebin.com/Ede3JwdG

The problem should be immediately evident: in Chrome, the first list item in the second column bleeds back into the first column. As you remove list items (click on them), you can see that alignment breaks down further.

I've tried tweaking the padding/margin for the list items to no avail: Chrome appears to have a flawed algorithm for how it flows content across a multi-column layout.

The primary reason I haven't ditched column-count altogether (in favor of manual generation/Columnizer/etc.) is that the menu system also involves drag-and-drop functionality across multiple sub-menus, and having the menu data laid out as a cohesive list-based hierarchy makes for clean code.

Is there a way to fix the alignment issue in Chrome or should I just give up on column-count for now?

ADDED:

TylerH
  • 20,799
  • 66
  • 75
  • 101
Ben D
  • 845
  • 1
  • 7
  • 9
  • 1
    it's good that you posted a link to your code, but it would be more helpful if you pasted a prototype here: http://jsfiddle.net that way people can play around with your code and provide you with a working prototype. welcome to SO! – corroded Mar 15 '11 at 16:30
  • 1
    Added jsFiddle and JS Bin links. – Ben D Mar 15 '11 at 16:43

12 Answers12

90

You need each item in the column to be displayed as "inline-block". That will solve your problem without needing to use jQuery.

Additionally, each element can be specified to have width: 100% in order to get the them to use the full width of the rows.

Here is a working example:

$(document).ready(function() {
    for( var i = 0; i < 24; i++ ) {
        $("ul.newslist").append("<li><a href='#'>Item</a></li>");
    }
    $("ul.newslist > li").click(function() {
        $(this).remove();
    })
});
ul.newslist {
    columns: 5;
    background-color: #ccc;
    padding: 16px 0;
    list-style: none;
}

ul.newslist > li {
    display: inline-block;
    width: 100%;
    border-top: 1px solid #000;
}

ul.newslist > li > a {
    display: block;
    padding: 4px;
    background-color: #f6b;
    text-decoration: none;
    color: inherit;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul class="newslist"></ul>
asiby
  • 3,229
  • 29
  • 32
  • 3
    Using display: inline-block; helped resolve the issue for us in Chrome (FF OK) but we had to use this on the grandchild element to get it to work. – BrochanGuMor Mar 01 '17 at 21:33
  • 21
    For short li elements use `width:100%` among `display:inline-block` to keep 1 item per row in the columns. – err Sep 02 '17 at 23:52
  • This works excellently for `li`, but I cannot get it to work for `dd`/`dt`. – Canned Man Aug 09 '21 at 01:08
  • 1
    Update: I retried the edit today, and for some reason it now works brilliantly. Thank you so much! – Canned Man Nov 26 '21 at 10:30
23

I managed to balance uneven vertically-aligned columns by applying margin-* properties to the elements inside the multicolumn'd container.

.content {
  column-width: 15em; /* or could be column-count, however you want to set up multi columns */
}
.content > section {
  -webkit-margin-before: 0;
  -webkit-margin-after: 0;
}
mahemoff
  • 44,526
  • 36
  • 160
  • 222
kmerc
  • 239
  • 2
  • 2
  • 6
    It's worth noting you should add these rules to the contents of column wrapper and not the column wrapper itself. Worked perfectly for me. – Ash Oct 04 '12 at 10:16
  • 1
    One issue with long column items: If a column item spans two or more lines and the item is the last one of the column and each column only contains two items then the second line ends up in the next column. – Daniel A. R. Werner Feb 02 '16 at 12:22
  • 1
    Didn't help for me – vsync Jun 07 '16 at 15:52
18

As for vertical margins leakage. You can replace margin with pseudo-element. Then set its height to desired margin value. You also need to set -webkit-column-break-inside: avoid; on the element containing pseudo-element so that it is not moved to another column. Do that only for webkit with the help of css-hack (not recommended) or js-detection (best way). Here is CSS:

.element {
  -webkit-column-break-inside: avoid;
}
.element:after {
  content: '';
  display: block;
  height: 20px;
}
Community
  • 1
  • 1
Andrey
  • 1,018
  • 12
  • 21