CoachNono CoachNono - 3 months ago 12
CSS Question

How to center a flex container but left-align flex items

I want the flex items to be centered but when we have a second line, to have 5 (from image below) under 1 and not centered in the parent.

enter image description here

Here's an example of what I have:



ul {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
margin: 0;
padding: 0;
}
li {
list-style-type: none;
border: 1px solid gray;
margin: 15px;
padding: 5px;
width: 200px;
}

<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
</ul>





http://jsfiddle.net/8jqbjese/2/

Answer

Flexbox Challenge & Limitation

Although I'm a big fan of flexbox, in its current state of evolution, it's not always the best solution for a layout. In other words, it can't do everything (yet). This question is a case in point.

The challenge is to center a group of flex items and left-align them on wrap. But unless there is a fixed number of boxes per row, and each box is fixed-width, this is currently not possible with flexbox.

Using the code posted in the question, we could create a new flex container that wraps the current flex container (ul), which would allow us to center the ul with justify-content: center.

Then the flex items of the ul could be left-aligned with justify-content: flex-start.

#container {
    display: flex;
    justify-content: center;
}

ul {
    display: flex;
    justify-content: flex-start;
}

This creates a centered group of left-aligned flex items.

The problem with this method is that at certain screen sizes there will be a gap on the right of the ul, making it no longer appear centered.

enter image description here enter image description here

This happens because when a flex item wraps, the container:

  1. doesn't know that the space is now empty, and
  2. doesn't recalculate its width to shrink-wrap the narrower layout.

The maximum length of the whitespace on the right is the length of the flex item that the container was expecting to be there.

By re-sizing the window horizontally back and forth, you can see the right spacing come and go.

DEMO


A More Practical Approach

The desired layout can be achieved without flexbox using inline-block and media queries.

HTML

<ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
</ul>

CSS

ul {
    margin: 0 auto;                  /* center container */
    width: 1200px;
    padding-left: 0;                 /* remove list padding */
    font-size: 0;                    /* remove inline-block white space;
                                        see http://stackoverflow.com/a/32801275/3597276 */
}

li {
    display: inline-block;
    font-size: 18px;                 /* restore font size removed in container */
    list-style-type: none;
    width: 150px;
    height: 50px;
    line-height: 50px;
    margin: 15px 25px;
    box-sizing: border-box;
    text-align: center;
}

@media screen and (max-width: 430px) { ul { width: 200px; } }
@media screen and (min-width: 431px) and (max-width: 630px) { ul { width: 400px; } }
@media screen and (min-width: 631px) and (max-width: 830px) { ul { width:600px;  } }
@media screen and (min-width: 831px) and (max-width: 1030px) { ul { width: 800px; } }
@media screen and (min-width: 1031px) and (max-width: 1230px) { ul { width: 1000px; } }

The above code renders a horizontally-centered container with left-aligned child elements like this:

enter image description here

DEMO


Other Options