How to set gaps (gutters) in a flex container?
Asked Answered
P

3

23

I'm trying to create some kind of universal component of flex container. This component consists of container and its children in a row.

If there are too many children in a line, those who don't have enough space go to second line. It can be easily achieved with flexbox, but also I want to be able to set gutter between elements. And first and last elements of a line shouldn't have left and right margin respectively.

I do this using negative margin technique, but the problem here is that right margin can provoke overflow issues if container is too big. I can solve this problem adding overflow: hidden to cut off negative margin, but it provokes problem with overflowing items inside container (drop-downs, etc).

So now I'm looking for silver bullet, implementation which can satisfy this requirements:

  • There are multiple items in a row. Width of items can differ.
  • If some items have not enough space, they go to next line.
  • There is a gap between items (margin), and first and last item doesn't have left and right margin, respectively.
  • Inside container can be placed overflowing content (drop-downs), so I can't use overflow: hidden
  • Css grid and flexbox can be used

Here is my solution of this problem: https://jsbin.com/gabumax

And here code from example:

.container {
  overflow: hidden;
}

.wrapper {
  margin: -10px;
  display: flex;
  flex-wrap: wrap;
}

.item {
  flex: 0 0 auto;
  padding: 10px;
  background-color: red;
  margin: 10px;
}
<div class="container">
  <div class="wrapper">
    <div class="item">Width of items can vary</div>
    <div class="item">This example works</div>
    <div class="item">But there is a problem</div>
    <div class="item">Dye to overlow:hidden</div>
    <div class="item">It is impossible to place here</div>
    <div class="item">Overflowing content</div>
    <div class="item">Such as dropdowns</div>
  </div>
</div>

It works, but the only negative point here is overlow: hidden. Because of this I can't place here dropdowns and other overflowing content.

Any better solution? Thanks in advance.

Pepsinogen answered 10/7, 2019 at 19:41 Comment(0)
S
48

Use gap / row-gap / column-gap:

.wrapper {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}

See more here

Surety answered 29/12, 2021 at 18:25 Comment(1)
This is the solution as of ‘now’, with support in all major browsers. For specification and compatibility see: developer.mozilla.org/en-US/docs/Web/CSS/gapSyllabary
V
4

To avoid the scrollbar to show, you may set your negative margin on the left and top only.

body {
  margin: 0;
}

.container {
  width:31.7em;
  max-width:100%;
  margin:auto;;
  background:yellow; 
}

.wrapper {
   display: flex;
  flex-wrap: wrap;
  margin-left:-10px;
  margin-top:-10px;
}

.item {
  flex: 0 0 auto;  
  padding: 10px;  
  background-color: red;  
  margin:10px  0  0 10px;
}
<div class="container">
  <div class="wrapper">
    <div class="item">Width of items can vary</div>
    <div class="item">This example works</div>
    <div class="item">But there is a problem</div>
    <div class="item">Dye to overlow:hidden</div>
    <div class="item">It is impossible to place here</div>
    <div class="item">Overflowing content</div>
    <div class="item">Such as dropdowns</div>

  </div>
</div>

or negative right margin if document dir is rtl

body {
  margin: 0;
  direction:rtl;
}

.container {
  width:31.7em;
  max-width:100%;
  margin:auto;;
  background:yellow; 
}

.wrapper {
   display: flex;
  flex-wrap: wrap;
  margin-right:-10px;
  margin-top:-10px;
}

.item {
  flex: 0 0 auto;  
  padding: 10px;  
  background-color: red;  
  margin:10px 10px  0  0;
}
<div class="container">
  <div class="wrapper">
    <div class="item">Width of items can vary</div>
    <div class="item">This example works</div>
    <div class="item">But there is a problem</div>
    <div class="item">Dye to overlow:hidden</div>
    <div class="item">It is impossible to place here</div>
    <div class="item">Overflowing content</div>
    <div class="item">Such as dropdowns</div>

  </div>
</div>
Vann answered 10/7, 2019 at 21:13 Comment(1)
This is such a brilliant simple solution. You have saved me a whole world of pain :) Thanks!!Masefield
L
3

Flexbox isn't your best option here. As you describe, gutter solutions are clumsy and inefficient.

A clean and efficient solution is possible with CSS Grid.

Grid wins over flexbox in this area for now because Grid accepts the gap properties. These properties are not yet available in flex but, as browsers continue to implement the CSS Box Alignment Module, the gap properties will be available across multiple box models (including flex).

§ Gaps Between Boxes

While margin and padding can be used to specify visual spacing around individual boxes, it’s sometimes more convenient to globally specify spacing between adjacent boxes within a given layout context, particularly when the spacing is different between boxes as opposed to between the first/last box and the container’s edge.

The gap property, and its row-gap and column-gap sub-properties, provide this functionality for multi-column, flex, and grid layout.

.wrapper {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  grid-auto-rows: 50px;
  grid-gap: 10px;
}

.item {
  padding: 10px;
  background-color: red;
}

body {
  margin: 0;
}
<div class="container">
  <div class="wrapper">
    <div class="item">Width of items can vary</div>
    <div class="item">This example works</div>
    <div class="item">But there is a problem</div>
    <div class="item">Dye to overlow:hidden</div>
    <div class="item">It is impossible to place here</div>
    <div class="item">Overflowing content</div>
    <div class="item">Such as dropdowns</div>
  </div>
</div>

jsFiddle demo

Lemuel answered 10/7, 2019 at 19:51 Comment(3)
Thanks for answer! But css-grid has serious disadvangage: using this technique I can't have items of different width. My aim is to have multiple items of different width (each item has it's own width depending of it's contents). Can I achieve this with css grid?Pepsinogen
Try switching 1fr to min-content in the minmax() function. You have multiple options. Just depends on your specific requirements.Lemuel
Firefox now supports gap in Flex layouts: caniuse.com/#feat=flexbox-gapBaumgardner

© 2022 - 2024 — McMap. All rights reserved.