36
votes

I was under the impression that a margin can be added to flex items/children, and flexbox should automatically take that into account and calculate the correct spacing between the items.

I can't seem to get this working as I would like though.

Fiddle here: https://jsfiddle.net/dba5ehcw/1/

.flex-item{
    border: 1px solid blue;
    box-sizing: border-box;
    height: 160px;
    width: 50%;
}

So each flex item at the moment is half the width of the container, and they flow nicely next to each other.

I would like to be able to add a margin of say, 1em to the flex-items in order to give them some breathing room, but in doing so, they become larger than the 50% and no longer stack next to each other on the same line because they are too wide.

Is there a way to use margin on the flex-items and have the flexbox container take this into account and adjust (decrease) their widths accordingly?

3

3 Answers

33
votes

You need to do it with padding - which, when in border-box mode does not make the container larger than it's specified width - not margin, and a nested flex div. This is how all flexbox-based grid systems work. Code below:

.flex-container{
    border: 1px solid red;
    box-sizing: border-box;
    display: flex;
    flex-wrap: wrap;
    width: 320px;
}

.flex-item{
    padding:1em;
    box-sizing: border-box;
    height: 160px;
    width: 50%;
    display:flex;
}

.flex-item>div {
    border: 1px solid blue;
    flex: 1 1 auto;
}
<div class="flex-container">
    <div class="flex-item"><div></div></div>
    <div class="flex-item"><div></div></div>
    <div class="flex-item"><div></div></div>
    <div class="flex-item"><div></div></div>
    <div class="flex-item"><div></div></div>
    <div class="flex-item"><div></div></div>
</div>
35
votes

There are multiple ways to do this:

  • Use calc:

    .flex-item {
      width: calc(50% - 2em);
      margin: 1em;
    }
    

    .flex-container {
      border: 1px solid red;
      box-sizing: border-box;
      display: flex;
      flex-wrap: wrap;
      width: 320px;
    }
    .flex-item {
      border: 1px solid blue;
      box-sizing: border-box;
      height: calc(160px - 2em);
      width: calc(50% - 2em);
      margin: 1em;
    }
    <div class="flex-container">
      <div class="flex-item"></div>
      <div class="flex-item"></div>
      <div class="flex-item"></div>
      <div class="flex-item"></div>
      <div class="flex-item"></div>
      <div class="flex-item"></div>
    </div>
  • Use nested boxes:

    .flex-item {
      width: 50%;
      display: flex;
    }
    .flex-item > div {
      border: 1px solid blue;
      flex: 1;
      margin: 1em;
    }
    

    .flex-container {
      border: 1px solid red;
      box-sizing: border-box;
      display: flex;
      flex-wrap: wrap;
      width: 320px;
    }
    .flex-item {
      height: 160px;
      width: 50%;
      display: flex;
    }
    .flex-item > div {
      border: 1px solid blue;
      flex: 1;
      margin: 1em;
    }
    <div class="flex-container">
      <div class="flex-item"><div></div></div>
      <div class="flex-item"><div></div></div>
      <div class="flex-item"><div></div></div>
      <div class="flex-item"><div></div></div>
      <div class="flex-item"><div></div></div>
      <div class="flex-item"><div></div></div>
    </div>
  • Place each row in a nowrap container, and use a positive flex-shrink factor

    .row {
      display: flex;
    }
    .flex-item {
      width: 50%;
      margin: 1em;
    }
    

    .flex-container {
      border: 1px solid red;
      width: 320px;
    }
    .row {
      height: 160px;
      display: flex;
    }
    .flex-item {
      border: 1px solid blue;
      width: 50%;
      margin: 1em;
    }
    <div class="flex-container">
      <div class="row">
        <div class="flex-item"></div>
        <div class="flex-item"></div>
      </div>
      <div class="row">
        <div class="flex-item"></div>
        <div class="flex-item"></div>
      </div>
      <div class="row">
        <div class="flex-item"></div>
        <div class="flex-item"></div>
      </div>
    </div>
  • Don't use width. Instead, force line-breaks at the right places, and use flex: 1 to make the elements grow to fill remaining space.

    .flex-item {
      flex: 1;
    }
    .line-break {
      width: 100%
    }
    

    .flex-container {
      border: 1px solid red;
      box-sizing: border-box;
      display: flex;
      flex-wrap: wrap;
      width: 320px;
    }
    .flex-item {
      border: 1px solid blue;
      box-sizing: border-box;
      height: calc(160px - 2em);
      flex: 1;
      margin: 1em;
    }
    .line-break {
      width: 100%;
    }
    <div class="flex-container">
      <div class="flex-item"></div>
      <div class="flex-item"></div>
      <div class="line-break"></div>
      <div class="flex-item"></div>
      <div class="flex-item"></div>
      <div class="line-break"></div>
      <div class="flex-item"></div>
      <div class="flex-item"></div>
    </div>
2
votes

Try this : -

.flex-container {
  border: 1px solid red;
  box-sizing: border-box;
  display: flex;
  flex-wrap: wrap;
  width: 320px;
}

.flex-item {
  justify-content: space-around;
  margin: 1%;
  background: red;
  border: 1px solid blue;
  box-sizing: border-box;
  height: 160px;
  width: 48%;
}
<div class="flex-container">
  <div class="flex-item"></div>
  <div class="flex-item"></div>
  <div class="flex-item"></div>
  <div class="flex-item"></div>
  <div class="flex-item"></div>
  <div class="flex-item"></div>
</div>