40

I currently have this simple Flexbox layout:

ul {
  display: flex;
  flex-wrap: wrap;
  list-style: none;
  padding: 0;
}
li {
  flex-grow: 1;
  padding: 20px;
  margin: 10px;
  background: #ddd;
}
<ul>
    <li>lorem</li>
    <li>ipsum</li>
    <li>dolor</li>
    <li>sit</li>
    <li>amet</li>
    <li>consectetur</li>
    <li>adipisicing</li>
    <li>elit</li>
    <li>sed</li>
    <li>do</li>
    <li>eiusmod</li>
    <li>tempor</li>
    <li>incididunt</li>
    <li>ut</li>
    <li>labore</li>
    <li>et</li>
    <li>dolore</li>
    <li>magna</li>
    <li>aliqua</li>
</ul>

I would like my elements to fill the container width (as now), but leave the last line left aligned. As you can see, the last line attempts to fill the space, and this sometimes makes the last elements to get an ugly width.

Does Flexbox allows us to do that ? I can't find a way to do it.

zessx
  • 68,042
  • 28
  • 135
  • 158
  • See answer here: https://stackoverflow.com/questions/16377972/how-to-align-left-last-row-line-in-multiple-line-flexbox?noredirect=1&lq=1 – Isaac Gregson Jun 23 '17 at 21:28
  • It was the first solution that came to my mind, but I'm not a big fan of adding extra markup. Plus, this only works for fixed-width elements, so this won't work here. – zessx Jun 24 '17 at 19:48
  • If your items have the same width, it is better to use [CSS grid](https://css-tricks.com/snippets/css/complete-guide-grid/). For 3 columns: `display:grid;grid-template-columns:33.3% 33.3% 33.3%`. – totymedli Jun 22 '18 at 11:35

6 Answers6

69

You can add an ::after pseudo-element with a huge flex-grow, so that the flex-grow: 1 of the li elements will be negligible:

ul::after {
  content: '';
  flex-grow: 1000000000;
}

ul {
  display: flex;
  flex-wrap: wrap;
  list-style: none;
  padding: 0;
}
li {
  flex-grow: 1;
  padding: 20px;
  margin: 10px;
  background: #ddd;
}
ul::after {
  content: '';
  flex-grow: 1000000000;
}
<ul>
  <li>lorem</li>
  <li>ipsum</li>
  <li>dolor</li>
  <li>sit</li>
  <li>amet</li>
  <li>consectetur</li>
  <li>adipisicing</li>
  <li>elit</li>
  <li>sed</li>
  <li>do</li>
  <li>eiusmod</li>
  <li>tempor</li>
  <li>incididunt</li>
  <li>ut</li>
  <li>labore</li>
  <li>et</li>
  <li>dolore</li>
  <li>magna</li>
  <li>dolore</li>
  <li>magna</li>
  <li>aliqua</li>
</ul>
Oriol
  • 274,082
  • 63
  • 437
  • 513
9

You can also append empty items with height: 0 to the container and make them take up for the extra space: http://codepen.io/anon/pen/OyOqrG

(Source copied from my codepen:

<div class="container">
  <p></p>
  <p></p>
  <p></p>
  ...
  <p class="empty"></p>
  <p class="empty"></p>
</div>



.container {
  max-width: 490px;
  display: flex;
  flex-flow: row wrap;
  background-color: #00f;
}

.container p {
  min-width: 90px;
  margin: 5px;
  background-color: #f00;
  height: 90px;
  flex-grow: 1;
}

.container p.empty {
  height: 0;
  margin-top: 0;
  margin-bottom: 0;
}
NiklasN
  • 559
  • 1
  • 7
  • 12
  • 1
    That's genius, it fits more responsive situations than the `flex-grow: 1000000000;` solution. Append n-1 `` as the number of max col in your grid, IE : I have 4 columns max on bigger screens, 3 `.empty` will fit every responsive situation – Xavier C. Jun 28 '21 at 15:23
6

Faced the same problem and solved it with css grid. Last rule of the grid is aligned left and all the elements have the same width.

grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));

ul {
  display: grid;
  gap: 10px;
  grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
  list-style: none;
  padding: 0;
}
li {
  padding: 20px;
  background: #ddd;
}
<ul>
    <li>lorem</li>
    <li>ipsum</li>
    <li>dolor</li>
    <li>sit</li>
    <li>amet</li>
    <li>consectetur</li>
    <li>adipisicing</li>
    <li>elit</li>
    <li>sed</li>
    <li>do</li>
    <li>eiusmod</li>
    <li>tempor</li>
    <li>incididunt</li>
    <li>ut</li>
    <li>labore</li>
    <li>et</li>
    <li>dolore</li>
    <li>magna</li>
    <li>aliqua</li>
</ul>
  • 1
    That is the way to go, nowadays. Thanks for sharing. – velop May 05 '22 at 17:26
  • Completely fixed my problem and made me learn more about grid in the process, upvoted – Nathan G-T Jul 11 '22 at 19:28
  • Use `auto-fill` instead of `auto-fit` to ensure that if you only have one element, it doesn't stretch the whole row. [here](https://css-tricks.com/auto-sizing-columns-css-grid-auto-fill-vs-auto-fit/) is an article with the difference between the two – Yonah Karp Mar 19 '23 at 03:31
1

You can set the pseudo ::last-child. All <li> grow except last one

CSS

ul {
  display: flex;
  flex-wrap: wrap;
  list-style: none;
  padding: 0;
}
li {
  flex-grow: 1;
  padding: 20px;
  margin: 10px;
  background: #ddd;
}

li:last-child {
  flex-grow: 0;
 }

DEMO HERE

Luís P. A.
  • 9,524
  • 2
  • 23
  • 36
  • 7
    Pretty close, but we still have the problem with items on the last line, which are **not** the last child. We would need a `::last-line` pseudo-element. – zessx May 18 '15 at 15:55
1

You can remove flex-grow: 1 on li and add justify-content: space-between on ul

ul {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  list-style: none;
  padding: 0;
}
li {
  padding: 20px;
  margin: 10px;
  background: #ddd;
}
<ul>
    <li>lorem</li>
    <li>ipsum</li>
    <li>dolor</li>
    <li>sit</li>
    <li>amet</li>
    <li>consectetur</li>
    <li>adipisicing</li>
    <li>elit</li>
    <li>sed</li>
    <li>do</li>
    <li>eiusmod</li>
    <li>tempor</li>
    <li>incididunt</li>
    <li>ut</li>
    <li>labore</li>
    <li>et</li>
    <li>dolore</li>
    <li>magna</li>
    <li>aliqua</li>
</ul>
Bluety
  • 1,869
  • 14
  • 22
  • 2
    Ow... the last line is unfortunately not left-aligned (if we've got more than one element) – zessx May 18 '15 at 15:57
  • The `li` elements won't grow in this case, so there will be gaps between their backgrounds. Still, that might be fine for some situations. – David Cook Feb 04 '22 at 04:09
-1

UPDATE: Turns out I didn't understand correctly, I misread the question as looking to target only the last item in the list, rather than the last line. Will leave the below here, though, for the benefit of anyone who trips over this question in the future and may find it helpful.

If I'm understanding you correctly then, to achieve what you want, you'll need to set the flex-grow property on all but the last item which you can do by combining the negation pseudo class :not() with the :last-child pseudo class, like so:

ul {
  display: flex;
  flex-wrap: wrap;
  list-style: none;
  padding: 0;
}
li:not(:last-child) {
  flex-grow: 1;
}
li {
  padding: 20px;
  margin: 10px;
  background: #ddd;
}
<ul>
    <li>lorem</li>
    <li>ipsum</li>
    <li>dolor</li>
    <li>sit</li>
    <li>amet</li>
    <li>consectetur</li>
    <li>adipisicing</li>
    <li>elit</li>
    <li>sed</li>
    <li>do</li>
    <li>eiusmod</li>
    <li>tempor</li>
    <li>incididunt</li>
    <li>ut</li>
    <li>labore</li>
    <li>et</li>
    <li>dolore</li>
    <li>magna</li>
    <li>aliqua</li>
</ul>
Shaggy
  • 6,696
  • 2
  • 25
  • 45