CSS multi-column layout of list items doesn't align properly in Chrome
Asked Answered
T

12

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:

Tweeny answered 15/3, 2011 at 16:24 Comment(2)
it's good that you posted a link to your code, but it would be more helpful if you pasted a prototype here: jsfiddle.net that way people can play around with your code and provide you with a working prototype. welcome to SO!Whensoever
Added jsFiddle and JS Bin links.Tweeny
H
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>
Horbal answered 20/2, 2017 at 16:22 Comment(4)
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.Slim
For short li elements use width:100% among display:inline-block to keep 1 item per row in the columns.Saari
This works excellently for li, but I cannot get it to work for dd/dt.Agio
Update: I retried the edit today, and for some reason it now works brilliantly. Thank you so much!Agio
S
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;
}
Soup answered 6/3, 2012 at 11:2 Comment(3)
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.Effable
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.Riplex
Didn't help for mePoinciana
I
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;
}
Isom answered 11/10, 2015 at 23:27 Comment(2)
That really helped! thanks (only -webkit-column-break-inside:avoid)Poinciana
Moving margin + padding from the <li> to the <a> and then applying break-inside: avoid; to the <li> worked for me. css-tricks.com/almanac/properties/b/break-inside was really helpful.Malloy
G
17

I've played around as well, and several sources I've seen online make it seem to be a known issue with webkit. A good breakdown can be found here: http://zomigi.com/blog/deal-breaker-problems-with-css3-multi-columns/

Someday, CSS 3!

Maybe try a jQuery plugin like http://welcome.totheinter.net/columnizer-jquery-plugin/ ?

Galleon answered 15/3, 2011 at 16:46 Comment(2)
Found my answer in the breakdown article you linked: display: inline-block Added that property to my menu items as well as a fixed width and the column-flow bug was resolved. Thanks a million for leading me to that article!Tweeny
@BenD. perhaps you could put the answer as it's own answer on this question?Wahhabi
S
7

I was having trouble with vertical alignment on a multi-column list. Turned out that the problem was that I was using bottom padding on my list li's-- I changed the li style to use a bottom margin instead, and the columns aligned to top again.

Sewoll answered 13/3, 2015 at 23:38 Comment(0)
F
3

My desired outcome was wanting to get a large list of links to display across 3 columns. Simply using column-break-inside:avoid; alone didn't work in webkit.

HTML

<div class="links">
  <ol>
    <li><a>link</a></li> <!-- x 50 -->
  </ol>
</div>

css:

.links ol {
  -webkit-column-count: 3;
  -moz-column-count: 3;
  column-count: 3;
}

.links li {
  display: block;
  border: 1px solid $background-colour; //to appear invisible
  -moz-column-break-inside:avoid;
  -webkit-column-break-inside:avoid;
  column-break-inside:avoid;
}

.links a {
  display: block;
  margin-bottom: 10px;
}

Solution (quirk if you will)

I added a 1px border around the list items which seemed to contain the margins of it's children and each column then aligned to the top.

Edit: This only seems to be required if you're using global border-box

html {
  box-sizing: border-box;
}
*, *:before, *:after {
  box-sizing: inherit;
}
Futurism answered 18/11, 2016 at 9:22 Comment(0)
B
2

I solved this by removing vertical margins on the child elements, and then increasing the line-height of the children to replicate desired spacing.

I also noticed I could fix this vertical alignment issue by removing the child margins and converting it to grandchild padding.

Banshee answered 19/12, 2016 at 22:14 Comment(0)
V
0

I'm struggling with this as well, for a reporting system with many many data and titles with padding/margin that I need to flow on several columns for wider screens.

I've worked around my first big deal-breaker, the padding of the initial title element, with the :first-child pseudo-class (this is included in an @media rule for wide screens not shown here) :

The columns definition :

.dimSlider .multicol {
  -moz-columns: 4;
  -webkit-columns: 4;
  columns: 4;
}

Canceling padding on top when in .multicol

.dimSlider .multicol h3 {
  padding-top: 0;
}

Cancelling padding and margin for the first element (color: blue; is so that I see if the rule catches) :

.dimSlider .multicol .criteria:first-child h3 {
  padding: 0 2%;
  margin: 0;
  color: blue;
}

So far, this looks way much neater in my Firefox. I'll see if there's some more tinkering to do but currently in Firefox the text looks aligned on the top, what is the most important.

EDIT : The problem seems quite worse with webkit-based browsers indeed. To solve it entirely, I modified the template in order to have a <div></div>around all the titled sections so I can add padding / margin at the end of the divs and not at the beginning of the titles. Now in webkit browsers it looks fine too.

BTW, using percentages measurements in multicolumns is quite tricky because the percentage seems calculated to the width of the column and not the global width of the parent element. I changed this by adding padding in the parent element of the columns.

But the biggest difficulty is that Firefox doesn't support any column-span or break-inside property, so when I have very few content, it is spread over the columns nonetheless, like one or two lines on each. Again, Smarty on the rescue :

{if $element|@count <= 10}
<div class="nocol"> 
{/if} 

So far it works now for me...

Vet answered 26/10, 2016 at 9:53 Comment(0)
A
0

while searching for information about this i came across your question and today I've been inspecting the elements of the list.

I found that the UL element applies a margin only on the first column.

Just apply 0 padding and margin in the css and they will align

margin:0;
padding:0;

hope it helps

Ackerman answered 5/7, 2020 at 12:26 Comment(0)
C
0

I had a two-column ordered list, and the left column was pushed down by default margin - so it did not align with the right column.

This fixed it.

ol > :first-child {
    margin-top: 0;
}
Crystallization answered 26/10, 2021 at 19:47 Comment(0)
D
0

I saw some solutions about placing -webkit-column-break-inside:avoid;. But that does not seems to work for me. Then I found out I have to place 2 things to get it working.

Place padding on the li, and give the property break-inside: avoid; on the li.

This is my code:

ul {     
    column-count: 2;
} 

li {
    font-size: 10px;
    line-height: 12px;
    padding: 10px 0;
    width: fit-content;
    min-width: 143px;
    border-bottom: 0.5px solid #ccc;
    break-inside: avoid;
}
Deepset answered 24/5, 2022 at 9:44 Comment(0)
G
-2

this is solution for multicolumn space problem

ul li { line-height:40px; }
Geometrician answered 20/7, 2017 at 12:25 Comment(1)
This will make multi line elements look like several elements.Aged

© 2022 - 2024 — McMap. All rights reserved.