4

I have a simple unordered list like so:

<ul class="flavours">   
     <li>Chocolate</li>
     <li>Caramel</li>
     <li>Watermelon</li>
</ul>

<ul class="flavours"> has a min-height of 200px and it grows as more <li> elements are added to the list via jQuery ui drag and drop library.

When there is just one or two <li> elements in the list, how can I vertically align these in the middle of the whole <ul>. So as when the height is 200px the items would be dead center, horizontally and vertically. Currently they are just positioned center top.

3 Answers3

3

Centering things vertically tends to be a tricky affair if you want cross-browser support, especially for IE and old browsers - unless you're willing to use JavaScript or a table. All common browsers support vertical centering within a table cell, so one option is to forget centering the <li> elements in the <ul> and instead create a table with height: 100% and one cell inside, with vertical-align: middle. It's not a popular answer but sometimes using a table is the most practical, as is well argued in this SO response.

If you do not want to use a table and can't use the display:table-cell for browser support, then you'll probably need to use JavaScript. Again, I would try to center the ul in a container, not the li in the ul. The approach is generally to find the height of the container, find the height of the ul, take the difference, cut it in half, and set the top or the margin-top of the ul to that value, depending on whether you want to use absolute positioning or not.

The exact best solution is hard to give without seeing the context of the list in your page.

Here's a fiddle using absolute positioning and JavaScript. Using margin-top and default position in this context is tricky because of margin collapse with the outer div, but if you can use it then you can use margin: 0 auto to do the horizontal centering, which is nice because then you can ignore the width.

Community
  • 1
  • 1
atw13
  • 719
  • 3
  • 7
  • Yeah, I could just use a table. I don't know what some people are so against tables. Yeah a table based layout is a no no but sometimes they are useful... like now. Thanks! –  Apr 03 '13 at 14:17
  • In this particular application, a small table with one-row once-cell will not significantly slow down the rendering of your web page. The real negative reaction to tables is for using tables to construct the entire layout of the page. – Marc Audet Apr 03 '13 at 14:27
  • @MarcAudet You don't choose or not choose to use tables for layout for performance reasons. The `` element is explicitly for tabular data and *should not* be used for layout (this is repeated *many* times in the Table specification). Modifying the display of the elements to give it the properties of table components is fair game.
    – cimmanon Apr 03 '13 at 14:30
  • @cimmanon I agree with you that tables are for tabular data. I was thinking of cases when `display: table-cell` may not be supported by an older browser, rare but still possible. – Marc Audet Apr 03 '13 at 14:32
  • @cimmanon is right in theory, and the chief reason is that you want to be able to change the visual layout without changing the semantics of the HTML - just the CSS. But IMO we're just not there yet. I, for instance, have a client that's a huge corporation that only uses IE 8. It's a shame but we do what we have to do. – atw13 Apr 03 '13 at 14:33
  • @atw13 IE8 supports `display: table`, its IE7 and older that's the problem. – cimmanon Apr 03 '13 at 14:40
  • Thanks @cimmanon. I didn't realize that. I'll start using it for IE8 requirements. Although now that I think about it, that client might be stuck on IE7! Another, lesser (for me) client is for sure. It's pretty ridiculous. – atw13 Apr 03 '13 at 14:57
3

Flexbox can do this:

http://jsfiddle.net/vUSmV/2/

.flavours {
  min-height: 10em;
  display: -webkit-box;
  display: -moz-box;
  display: -webkit-flexbox;
  display: -ms-flexbox;
  display: -webkit-flex;
  display: flex;
  -webkit-box-orient: vertical;
  -moz-box-orient: vertical;
  -webkit-box-direction: normal;
  -moz-box-direction: normal;
  -webkit-flex-direction: column;
  -ms-flex-direction: column;
  flex-direction: column;
  -webkit-box-pack: center;
  -moz-box-pack: center;
  -webkit-flex-pack: center;
  -ms-flex-pack: center;
  -webkit-justify-content: center;
  justify-content: center;
  -webkit-flex-align: center;
  -ms-flex-align: center;
  -webkit-align-items: center;
  align-items: center;

}

Using Flexbox with inline list items that wrap (note that wrapping reduces browser support to Chrome, Opera, and IE10):

http://jsfiddle.net/vUSmV/4/

.flavours {
  min-height: 10em;
  border: 1px solid;
  display: -webkit-flexbox;
  display: -ms-flexbox;
  display: -webkit-flex;
  -webkit-flex-wrap: wrap;
  -ms-flex-wrap: wrap;
  flex-wrap: wrap;
  -webkit-flex-pack: center;
  -ms-flex-pack: center;
  -webkit-justify-content: center;
  justify-content: center;
  -webkit-flex-line-pack: center;
  -ms-flex-line-pack: center;
  -webkit-align-content: center;
  align-content: center;
  -webkit-flex-align: center;
  -ms-flex-align: center;
  -webkit-align-items: center;
  align-items: center;
}
@supports (flex-wrap: wrap) {
  .flavours {
    display: flex;
  }
}

.flavours li {
    margin: .5em 1em;
}

Or you can convert your list into a table-cell element:

http://jsfiddle.net/vUSmV/1/

.flavours {
  min-height: 10em;
  display: table-cell;
  vertical-align: middle;
}
cimmanon
  • 67,211
  • 17
  • 165
  • 171
  • This works great, but is there a way to show the `
  • ` items `inline` in this fashion?
  • –  Apr 03 '13 at 14:25
  • The Flexbox way or table-cell way? Do the elements need to wrap? – cimmanon Apr 03 '13 at 14:28
  • I've added an example for horizontal list items – cimmanon Apr 03 '13 at 14:38