98

I have a major issue with flexbox layout. I build a container with a boxes filled with images, and i decided to use flexbox layout to justify the content to make it looks like a grid

Her's the code:

<div class="container">

    <div class="item"></div>
    <div class="item"></div>
    ...
    <div class="item"></div>

</div>

and the CSS:

.container {
    display: flex;
    display: -webkit-flex;
    display: -moz-flex;
    justify-content: space-around;
    -webkit-justify-content: space-around;
    -moz-justify-content: space-around;
    flex-flow: row wrap;
    -webkit-flex-flow: row wrap;
    -moz-flex-flow: row wrap;
}

.container .item { width: 130px; height: 180px; background: red; margin: 0 1% 24px; }

And everything looks good except the last line/row - when it not contain the same number of element that other lines, centering elements and it broke my grid effect.

http://jsfiddle.net/puz219/7Hq2E/

How to align last line/row to left side?

Community
  • 1
  • 1
PuZ
  • 983
  • 1
  • 7
  • 5
  • I removed the Flex tag as this has nothing to do with the Adobe/Apache UI framework. – JeffryHouser May 04 '13 at 19:38
  • 1
    Even if you could adjust the contents of only the last line, there's no way you could line up your elements because of space-around. The best you can do is use space-between instead: http://jsfiddle.net/7Hq2E/1/. Also, there is no moz prefix on the standard properties. They should be replaced with properties for IE10: https://gist.github.com/cimmanon/727c9d558b374d27c5b6 – cimmanon May 04 '13 at 23:54
  • 10
    Just remove justify-content from your code and it will work. You can fine tune the space between flex items with the margin property. [http://jsfiddle.net/katranci/kkRmW/](http://jsfiddle.net/katranci/kkRmW/) – katranci May 07 '13 at 12:22
  • 4
    I know this is old, but the comment katranci left is incorrect. If you don't justify the content, gaps develop on the right when resizing. Try resizing the width of each fiddle and watch the right side. You'll notice there is a HUGE difference. – Tim Hobbs May 16 '14 at 06:37
  • Check this out: http://stackoverflow.com/a/22018710/130169 – Geert Aug 18 '14 at 12:25
  • All you need is a preprocessor mixin, and a single line of code to use that mixin. See here: http://stackoverflow.com/a/36401995/635069 – Merott May 04 '16 at 09:31
  • I don't know where to put this comment, and it has nothing to do with the answer, so skip as needed. But how can this question be marked as "already been answered" and flagged as a duplicate when it was asked over a year *before* the linked answer was posted? – josh1978 Jun 21 '18 at 22:09

6 Answers6

131

Got it. (I think)(this is my first contribution here!)

Imagine a layout which needs to have 4 images per row. w:205 h:174 Problem: Using justify-content:space-around, if the last row doesn´t have 4 images (has 3, 2 or 1), they would not respect the grid, they would spread. So.

Create in the html 3 divs with the class "filling-empty-space-childs" like this.

.filling-empty-space-childs {
    width:205px; /*the width of the images in this example*/
    height:0; /*Important! for the divs to collapse should they fall in a new row*/
}

The flexbox container has display:flex / flex-wrap:wrap; / justify-content:space-around

The last row can have 4, 3, 2, 1 images. 4 images: no problem, this three divs would collapse in a new row since they have no height. 3 images: no problem, one div is going to be in the same row, invisible, and the other two would wrap to a new row, but will collapse since they have no height. 2 images: no problem, two divs are going to be in the same row, invisibles, the rest... collapsed 1 image: no problem, the three divs are going to fill in the space.

  • 4
    Hacky but genius. If using React, the extra (n - 1) filler divs can be well encapsulated in a wrapper component. – Dave Jul 22 '16 at 01:37
  • 4
    wow, really nice. This solution can be mixed with `:after` if you need 2 columns only. And it's also work with variable column number depending on screen size. Amazing! – farwayer Oct 28 '16 at 20:01
  • 1
    Genius answer! I would say even add more empty child than (n-1) still works well! – thomasdao Nov 02 '16 at 22:15
  • 4
    Here is a modification of the original jsFiddle that use this hack: http://jsfiddle.net/7Hq2E/172/ – Waruyama Dec 21 '16 at 12:32
  • 4
    This answer is the best. Not only it gives the solution - add as many empty containers as could ever be needed to fill the entire remaining with of the last row - and explains why it works - because even if there are less spaces than empty containers and they get moved to the next row, the next row still has height: 0 and layout doesn't change. Clever. – Robert Kusznier Feb 26 '17 at 17:30
  • 1
    Where this falls down is if you have a small number of items but a large containing box. The filler images will end up on the first line, thus not allowing the actual images to be centered on the first line. Nonetheless, if that's not a big deal to you, this works nicely. – duhseekoh Oct 04 '17 at 22:08
  • @farwayer I found the `:after` solution too, and it works with 3 columns as well, if you use `justify-content: space-between;` – LukasKroess Oct 03 '18 at 11:18
  • You are a genius man – Huan Zhang Jul 02 '19 at 19:03
  • Diabolic! Genius! I U MAN! – StelArian Oct 27 '20 at 03:11
  • Nice hack! Not the cleanest solution but considering flexbox limitations, this worked just fine for me. Thanks – Ken Mar 19 '21 at 12:27
  • {(new Array(emptyItemLen)).map( (_, idx) => (
    ))}
    – Robin May 08 '22 at 12:53
  • Cleanest hack! Absolute genius. – iamsubingyawali Aug 31 '22 at 16:47
  • Impressed! Although handcrafted, it serves the purpose. Bravo! – Agoun Nov 26 '22 at 01:15
54

Unfortunately this is not possible with flexbox.

The best work-around is to add invisible children 'filling up' the empty 'blocks' in the last row. That way, the actual, visible, element is aligned left.

Similar question: Flex-box: Align last row to grid

Community
  • 1
  • 1
sandstrom
  • 14,554
  • 7
  • 65
  • 62
  • 6
    Concise. This should be the accepted answer. – Alex Shesterov Mar 03 '15 at 23:10
  • 1
    I came up with a CSS only solution.. the caveat being it can only ever account for two missing items, so will only work safely in a flex grid with a maximum of three items per wrapping row. Demo: http://codepen.io/lukejacksonn/pen/dozqVq The principle here is to use pseudo elements as the "*invisible children*" and give them the same flex property as the items in the container. – lukejacksonn Jun 18 '15 at 19:43
  • And here is a well explained work around for that: https://css-tricks.com/filling-space-last-row-flexbox/ – Waleed Asender Sep 02 '15 at 08:45
  • 4
    @WaleedAsender No, that's to fill the space. He wants to left-align the last row to the same columns of the previous rows. It's probably the most-wanted missing feature of flexbox. – Matthew Dean Sep 20 '15 at 23:13
  • 1
    Excellent answer and I voted it up, but I don't think it should be marked as the accepted answer. I don't think there's any way to know how many invisible children to add because it changes with the size of the browser window. – Vince Jan 05 '16 at 11:52
23

You can use margin-right:auto on the last-child flex item.

The problem here is that you will lose the space-between property on the left for this flex item.

Hope it helps!

bzin
  • 1,921
  • 2
  • 14
  • 15
  • That only works for single last row. If there are two or more, they will share space and each will align right in that space. – mjs Jul 02 '16 at 18:32
9

I thought this example might be useful for anyone who wanted multiple items and allow for responsiveness, the grid items change depending on the viewport size. It does not use any invisible children, it's all done through css.

Might help someone trying align items to the left when the last row has less items and they require the page to be responsive.

http://codepen.io/kunji/pen/yNPVVb

Sample HTML

<div class="main-container">

    <div class="main-items-container">

        <div class="item-container">
          <h2>Item Name</h2>
        </div>

        <div class="item-container">
          <h2>Item Name</h2>
        </div>

        <div class="item-container">
          <h2>Item Name</h2>
        </div>

        <div class="item-container">
          <h2>Item Name</h2>
        </div>

        <div class="item-container">
          <h2>Item Name</h2>
        </div>

        <div class="item-container">
          <h2>Item Name</h2>
        </div>

    </div>

</div>

Sample CSS

.main-container {
  max-width: 1000px;
  min-width: 300px;
  margin: 0 auto;
  padding: 40px;
  box-sizing: border-box;
  border: 1px solid #000;
}

.main-items-container {
  display: -ms-flexbox;
  display: flexbox;
  display: -webkit-flex;
  display: -ms-flex;
  display: flex;
  padding: 0;
  margin: 10px 0;
  list-style: none;
  width: auto;
  -webkit-flex-flow: row wrap;
  justify-content: flex-start;
  -webkit-flex-wrap: wrap;
  flex-wrap: wrap;
  -webkit-align-items: stretch;
  align-items: stretch;
  box-sizing: border-box;
}

@media (min-width: 971px) {
  .item-container {
    margin: 10px 2%;
    width: 22%;
    padding: 10px;
    border: 1px solid #000;
    box-sizing: border-box;
  }
  .item-container:nth-child(4n+1) {
    margin-left: 0;
  }
  .item-container:nth-child(4n) {
    margin-right: 0;
  }
}

@media (min-width: 550px) and (max-width: 970px) {
  .item-container {
    margin: 10px 2.50%;
    width: 30%;
    padding: 10px;
    border: 1px solid #000;
    box-sizing: border-box;
  }
  .item-container:nth-child(3n+1) {
    margin-left: 0;
  }
  .item-container:nth-child(3n) {
    margin-right: 0;
  }
}

@media (max-width: 549px) {
  .item-container {
    margin: 10px 0;
    width: initial;
    padding: 10px;
    border: 1px solid #000;
    box-sizing: border-box;
  }
}
Kunji
  • 91
  • 1
  • 2
2

This is not an effect you wanted to achieve?

http://jsfiddle.net/7Hq2E/21/

CSS:

.container {
    display: flex;
    display: -webkit-flex;
    display: -moz-flex;
    flex-flow: row wrap;
    -webkit-flex-flow: row wrap;
    -moz-flex-flow: row wrap;
}
.container .item {
    width: 23%;
    height: 180px;
    background: red;
    margin: 0 1% 20px;
}

HTML:

<div class="container">
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
</div>
bashaus
  • 1,614
  • 1
  • 17
  • 33
Jonáš Krutil
  • 245
  • 1
  • 9
  • 1
    This approach would only work if you wanted the same number of elements to be able to fit on each line, regardless of the size of the container. The asker is using absolute units (px). He wants a behavior like the picture thumbnails in Windows Explorer, where the space between each item adjusts, the last row is left aligned, and the number of items on each row changes according to the space available. – tvanc Oct 02 '14 at 17:51
-2

I've checked it and it worked better in my HTML editor tool

the script should be the way

CSS Part

.container {
display: flex;
display: -webkit-flex;
display: -moz-flex;
justify-content: space-around;
-webkit-justify-content: space-around;
-moz-justify-content: space-around;
flex-flow: row wrap;
-webkit-flex-flow: row wrap;
-moz-flex-flow: row wrap;
}

.container .item { width: 130px; height: 180px; background: green; margin: 0 1% 24px; }

HTML Part

<div class="container">

    <div class="item"><a href='google.com'>Google</a></div>
    <div class="item"><a href='google.com'>Yahoo</a></div>
    <div class="item"><a href='google.com'>Bing</a></div>
</div>

<div class="container">
    <div class="item"><a href='google.com'>Google</a></div>
    <div class="item"><a href='google.com'>Yahoo</a></div>
    <div class="item"><a href='google.com'>Bing</a></div>

</div>


enter image description here

Brad Larson
  • 170,088
  • 45
  • 397
  • 571
Ahmed Wild
  • 132
  • 6
  • 1
    It only shows as a single column on jsfiddle, though. It's also not clear from the picture if it centers upon resize. Judging by the two containers, it won't dynamically create fewer/more rows as the viewport shrinks/grows. – HulkingUnicorn Mar 03 '14 at 11:52