zessx
zessx

Reputation: 68818

Flexbox : grow all items but last line

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.

Upvotes: 41

Views: 20871

Answers (6)

Michiel De Rycke
Michiel De Rycke

Reputation: 81

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>

Upvotes: 6

NiklasN
NiklasN

Reputation: 559

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;
}

Upvotes: 9

Shaggy
Shaggy

Reputation: 6796

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>

Upvotes: -1

Oriol
Oriol

Reputation: 288690

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>

Upvotes: 74

Bluety
Bluety

Reputation: 1909

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>

Upvotes: 1

Lu&#237;s P. A.
Lu&#237;s P. A.

Reputation: 9739

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

Upvotes: 2

Related Questions