103

I've recently been playing with Flexbox for the first time and, in general, it's absolutely amazing. I've encountered an issue recently however, where I cannot seem to give flex items that are wrapping any vertical spacing.

I've tried using:

align-content: space-between;

but this doesn't seem to do anything. From the reading I've done, this would only seem to work if my flex container is taller than the elements contained within (is this right?) If so, then would I not have to set a height for my flex-container, which would seem to defeat the purpose of using flexbox?

The only way I can think of to make this work would be to give bottom margin to the elements within, but again this seems to defeat the purpose.

Hopefully I'm missing something fairly obvious - here's a link to a codepen: http://codepen.io/lordchancellor/pen/pgMEPz

Also, here's my code:

HTML:

<div class="container">
   <div class="col-sm-12">
     <h1>Flexbox Wrapping</h1>

     <div class="flexContainer">
       <div class="flexLabel">This is a flex label</div>
                    
       <a class="btn btn-primary">Button 1</a>
       <a class="btn btn-warning">Button 2</a>
       <a class="btn btn-success">Button 3</a>
     </div>
   </div>
 </div>

CSS:

.flexContainer {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  align-content: space-between;
  justify-content: center;
}
.flexContainer .flexLabel {
  flex-basis: 150px;
  flex-shrink: 0;
}

EDIT - Just going to add a little more detail here, as I'm not sure I'm putting it across well enough.

In my larger project, I have some block level elements that are arranged in a row using flexbox. However, there needs to be some responsiveness as the user may reduce the screen width. At this point, I want my elements to begin to stack (hence the wrap). However, as the elements begin to stack, they are all touching vertically, where I want there to be spacing.

It's beginning to look like top and bottom margins may be the only way to resolve this - however I was wondering if there was a flexbox-centric way to achieve this.

PaulMest
  • 12,925
  • 7
  • 53
  • 50
lordchancellor
  • 3,847
  • 4
  • 26
  • 26

5 Answers5

74

I had a similar issue and I used the following hack to solve the issue.

    /* add a negative top-margin to the flex container */
.flexContainer {
        /* ... your existing flex container styles here */
    margin: -10px 0 0 0;
} 
    /* add a corresponding positive top margin to all flex items (all direct children of the flex container) */
.flexContainer > * {
    margin-top: 10px;
}

For the top row of flex items the negative and positive margins cancel out, for the subsequent rows it adds the margin between the rows (in this case 10px between rows).

It's less than elegant but it gets the job done.

JRulle
  • 7,448
  • 6
  • 39
  • 61
  • 2
    Why are negative margins considered a hack? – Casey Jan 31 '18 at 21:59
  • 1
    In this case, because this is not margin's desired use to fix flexbox gaps and margin is used in cooperation with another margin in another object to affect the appearance of the other object. So, this makes it less elegant because it can easily be considered bad practice for spaghetti logic (change object A to fix object B + unorthodox use of margin to fix flexbox). I think that the solution though is nice, apart from the hacky aspect of it which is not for OP to blame but CSS & browsers themselves for not having a clean way to solve this. – Eksapsy Nov 05 '19 at 10:01
  • 1
    Apparently that's the way to do it, at least according to Mozilla :) https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Mastering_Wrapping_of_Flex_Items#creating_gutters_between_items – Noam Gal Aug 11 '21 at 02:59
65

row-gap would solve your problem

.flexbox {
    display: flex;
    column-gap: 10px;
    row-gap: 10px
}
Fabian Amran
  • 833
  • 6
  • 11
48

If you force wrapping by applying a width you can then use margins as you normally would without setting a height.

.flexContainer {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  justify-content: center;
  background: pink;
  width: 150px;
}
.flexContainer > * {
  margin: 1em 0;
}
.flexContainer .flexLabel {
  flex-basis: 150px;
  flex-shrink: 0;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet" />

<div class="container">
  <div class="col-sm-12">
    <h1>Flexbox Wrapping</h1>

    <div class="flexContainer">

      <div class="flexLabel">This is a flex label</div>

      <a class="btn btn-primary">Button 1</a>
      <a class="btn btn-warning">Button 2</a>
      <a class="btn btn-success">Button 3</a>
    </div>

  </div>
</div>
Paulie_D
  • 107,962
  • 13
  • 142
  • 161
  • 1
    The no wrap seems to be a typo though because it's overwritten two lines later with `flex-wrap: wrap;` – tenor528 Feb 23 '16 at 13:25
  • 1
    Yes you're absolutely right, the nowrap was an idiotic typo, as I lifted this code snippet from my larger project! – lordchancellor Feb 23 '16 at 13:51
  • The question has been edited now but the fact remains is the the items are not wrapping because the parent is wide enough to accommodate them. – Paulie_D Feb 23 '16 at 13:53
  • So I take from this that the best solution is actually to pop some margin on the elements? That's fine - though I had thought that flexbox was supposed to eliminate the need to use margins to space out your elements. Thanks for your input @Paulie_D. – lordchancellor Feb 23 '16 at 13:54
  • 1
    It will space elements across a known height but not if you don't set one, how could it? – Paulie_D Feb 23 '16 at 13:56
  • I for one was hoping for something similar to `padding-top` as percentage of regular divs, that actually relates to width so it's useful in allowing uniform space around the elements. As it is now, horizontal distances are variable while vertical ones are set to fixed values, which doesn't always look nice. I'm wondering if there may be some hack around this. – lucian Jul 25 '16 at 11:10
  • This is a poor implementation though, there needs to be wrapSpacing property to solve this. – Oliver Dixon Jul 13 '19 at 12:27
  • 3
    @lordchancellor You probably already know this, but for those who don't, `column-gap` and `row-gap` are what to use to set vertical and horizontal gutters for flexbox displays. (I don't know how well they were supported in 2016.) You can also use `gap` to set both at once if they are the same. – BobRodes Sep 27 '20 at 03:34
  • @BobRodes `gap` doesn't seem to work with wrapping. If I have a row flexbox with a `gap` of `1%` set to `wrap` and it wraps onto the next line, there is space between items in one row, but no space between "rows" (the one wrapped row that spans multiple visual rows) – Adam Wójcik Apr 15 '23 at 10:16
  • @AdamWójcik Hmm. I'll take your word for it, and good thing to know. :) – BobRodes Apr 16 '23 at 17:23
7

It's because you don't have a height on your flex content for it to calculate the space-between so at the moment, the flex container is as small as possible. Add a height and it should work.

tenor528
  • 1,120
  • 13
  • 20
3

Another hacky solution is to give the item a bottom border:

border-bottom: 10px solid transparent;
Zohar
  • 1,820
  • 1
  • 18
  • 16