Better way to set distance between flexbox items
- Flexbox doesn't have collapsing margins.
- Flexbox doesn't have anything akin to
border-spacing
for tables (edit: CSS propertygap
fulfills this role in newer browsers, Can I use)
Therefore achieving what you are asking for is a bit more difficult.
In my experience, the "cleanest" way that doesn't use :first-child
/:last-child
and works without any modification on flex-wrap:wrap
is to set padding:5px
on the container and margin:5px
on the children. That will produce a 10px
gap between each child and between each child and their parent.
Demo
.upper {
margin: 30px;
display: flex;
flex-direction: row;
width: 300px;
height: 80px;
border: 1px red solid;
padding: 5px; /* this */
}
.upper > div {
flex: 1 1 auto;
border: 1px red solid;
text-align: center;
margin: 5px; /* and that, will result in a 10px gap */
}
.upper.mc /* multicol test */ {
flex-direction: column;
flex-wrap: wrap;
width: 200px;
height: 200px;
}
<div class="upper">
<div>aaa<br/>aaa</div>
<div>aaa</div>
<div>aaa<br/>aaa</div>
<div>aaa<br/>aaa<br/>aaa</div>
<div>aaa</div>
<div>aaa</div>
</div>
<div class="upper mc">
<div>aaa<br/>aaa</div>
<div>aaa</div>
<div>aaa<br/>aaa</div>
<div>aaa<br/>aaa<br/>aaa</div>
<div>aaa</div>
<div>aaa</div>
</div>
Css flexbox gutter with spacing
Your problem is that your divs are 1/3 their parent's width, but then when you add the margin in there, the total width goes over 100%. Unlike padding, which is counted as part of the element's width, margin is in addition to the element's width.
So there's two possible solutions here. The first is to set the width as 1/3 the parent width minus the desired margin. Since you used m-2
in your example, which appears to be .5rem
according to Tailwind, we would double that number to account for margins on both the right and left sides of each box, and end up with this:
.flex-wrap > div { width: calc(33.333333% - 1rem);}
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet"><div class="flex flex-wrap"> <div class="bg-red-500 p-4 m-2"> test </div> <div class="bg-red-500 p-4 m-2"> test </div> <div class="bg-red-500 p-4 m-2"> test </div> <div class="bg-red-500 p-4 m-2"> test </div> <div class="bg-red-500 p-4 m-2"> test </div> <div class="bg-red-500 p-4 m-2"> test </div></div>
Creating a flexbox grid with gutters and fixed widths
For various reasons, this job is better suited for CSS Grid than Flexbox.
First, getting the gutters to work in Grid is simple. You can use the grid-gap
property, which isn't available yet in flexbox.
Second, the "columns" you're requesting aren't really columns. A column has the same width from top to bottom. You're asking for a masonry layout, which allows content items to span across multiple columns and rows.
Again, this task is much easier to achieve with CSS Grid.
Here's one solution that may work for you (including the media query):
jsFiddle demo
.grid-container { display: grid; grid-auto-columns: 1fr; width: 500px; grid-auto-rows: 50px; grid-gap: 10px;}
.col-1 { grid-column: 1 / span 4; grid-row: 1;}
.col-2 { grid-column: 5 / span 6; grid-row: 1;}
.col-3 { grid-column: 1 / span 5; grid-row: 2;}
.col-4 { grid-column: 6 / span 5; grid-row: 2;}
.col-5 { grid-column: 1 / span 6; grid-row: 3;}
.col-6 { grid-column: 7 / span 4; grid-row: 3;}
@media ( max-width: 992px ) { .grid-container>div { grid-column: 1; grid-row: auto; }}
/* non-essential demo styles */
.grid-container { border: 1px solid black; background-color: lightgray;}.grid-container > div { font-size: 1.3em; color: white; display: flex; align-items: center; justify-content: center;}.grid-container > div:nth-child(odd) { background-color: green;}.grid-container > div:nth-child(even) { background-color: orangered;}
<div class="grid-container"> <div class="col-1">40%</div> <div class="col-2">60%</div> <div class="col-3">50%</div> <div class="col-4">50%</div> <div class="col-5">60%</div> <div class="col-6">40%</div></div>
CSS flex children gutters with margin
Method # 01:
Add following css on parnet and child respectively (This method will work only when there are only 2 boxes in a row):
/* For Parent Element */
.flex {
justify-content: space-between;
}
/* For Child Element */
.flex-child {
flex: 0 0 calc(50% - 0.5em);
}
* { box-sizing: border-box; margin: 0; padding: 0;}ul { list-style-type: none;}.flex { display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; display: flex; -webkit-flex-wrap: wrap; -ms-flex-wrap: wrap; flex-wrap: wrap;}.align-center { -webkit-box-align: center; -webkit-align-items: center; -ms-flex-align: center; align-items: center;}.space-between { -webkit-box-pack: justify; -webkit-justify-content: space-between; -ms-flex-pack: justify; justify-content: space-between;}.container { max-width: 1000px; margin: 0 auto; height: 100%; padding: 0 1em; border: 1px solid;}nav { background: #464646; height: 70px;}.box { background: lightblue; padding: 1em; -webkit-box-flex: 0; -webkit-flex: 0 0 calc(50% - 0.5em); -ms-flex: 0 0 calc(50% - 0.5em); flex: 0 0 calc(50% - 0.5em); text-align: center; margin-bottom: 1em;}
<nav> <div class="container flex align-center space-between"> <ul> <li>Logo</li> </ul> <ul> <li>Home</li> </ul> </div></nav><div class="container"> <header> <h1>Header</h1> </header></div><div class="container"> <div class="gallery flex space-between"> <div class="box">BOX 1</div> <div class="box">BOX 2</div> <div class="box">BOX 3</div> <div class="box">BOX 4</div> <div class="box">BOX 5</div> <div class="box">BOX 6</div> <div class="box">BOX 7</div> <div class="box">BOX 8</div> <div class="box">BOX 9</div> </div></div>
Creating a gap using flex
Flex doesn't work that way. If you want a gap in flex, you only have 2 alternative options:
1. Relative Gap
CSS3 offers devs 3 values for justify-content
property that help you to align the objects and creating gap between them relatively:
- space-around: Inserting gaps between its childern and 2 sides of them.
- space-between: Inserting only gaps between its childern.
- space-evenly: Similar to space-around but provides equal instead of half-sized space on the edges.
.container {
display: flex;
justify-content: /* put it in here */;
}
- You cannot fix gaps, so it may break you layout. Especially in the case where your container has loose width or height.
2. Fixed Gap
Using margin property to fix gaps between container's children. Sometime easy, but sometime... it could be quite annoying.
.container {
display: flex;
}
.container > * {
margin: /* top right bottom left | top-bottom right-left | etc. */;
}
- For complex task, selector
nth-child
is required. - It also requires more calculating.
How can I get `column-gap`'s effect with `display: flex` in Chrome?
Something like this?
.flex-container { display: flex; justify-content: space-between; border: 1px solid black;}.flex-item { flex-basis: 33%; height: 30px; margin-left: 10px; background-color: #cccccc; }.flex-item:first-child{ margin-left: 0}
<div class="flex-container"> <div class="flex-item"></div> <div class="flex-item"></div> <div class="flex-item"></div></div>
Adding space between flexbox items
There a few things you have to consider.
First of all; with justify-content
you define how remaining space is handled. By using space-between
your items will be aligned so that the space between them is equal, by setting it to center
the remaining space will be around all items, with all items stuck together.
In your case though, there is no remaining space, because your items actually stretch the div. So that doesn't help you.
Next; you've set the width of an item to 50%
. Which is fine, your item
's will be 50% of the viewport. That's because your grid will implicitly be 100% of the viewport. But because your image overflows the box, you can set margins if you want, and they will put the items further apart, but you need big-ass margins to actually see them. Bigger then the overflowing of your image.
So, to fix this, you make the images responsive by making them as width as the item;
.item img { display: block; height: auto; width: 100%; }
But that poses another problem; flexbox tries to size it's flex items to fit it all into the flex container. So you'll see that it automatically resizes your items so they will all fit in. To fix this, you have to explicitly force the width of your items;
.item { flex: 0 0 50%; }
Which is a shorthand for;
.item { flex-grow: 0; flex-shrink: 0; flex-basis: 50%; }
So basically you say; make my item 50% of it's container, and don't use your awesome algorithm to try to make it bigger or smaller.
Now you've got what you want, and you can use margin-right: 20px
for example to create a 20px space between your items.
Full snippet;
.grid { display: flex; width: 100%; }
.item { flex: 0 0 50%; margin-right: 20px; }.item img { display: block; height: auto; width: 100%; }
.article-scroll-mobile { box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2); flex-wrap: nowrap; text-align: center; overflow-x: auto; -webkit-overflow-scrolling: touch; /*For iOS smooth scroll effect*/}
<div class="grid article-scroll-mobile"> <div class="item"> <img src="https://www.w3schools.com/howto/img_fjords.jpg"> </div> <div class="item"> <img src="https://www.w3schools.com/howto/img_fjords.jpg"> </div> <div class="item"> <img src="https://www.w3schools.com/howto/img_fjords.jpg"> </div> <div class="item"> <img src="https://www.w3schools.com/howto/img_fjords.jpg"> </div> <div class="item"> <img src="https://www.w3schools.com/howto/img_fjords.jpg"> </div> <div class="item"> <img src="https://www.w3schools.com/howto/img_fjords.jpg"> </div></div>
Gaps between items only
To accomplish that, w/o using a script or media query, you will need a minor markup change.
With the extra wrapper
you then compensate the left margin set on the items,
so it will only be visible when wrapped.
Note, this trick is well known, since more or less all frameworks, like Bootstrap etc., use this to accomplish the same in their solutions. CSS Grid can do this much simpler, though due to lack of browser support, this is what's mostly used today.
Updated codepen
Stack snippet
body { margin: 0; background: black;}
.container { max-width: 700px; margin: 20px auto; overflow: hidden; /* added */}
.wrapper { display: flex; /*flex-direction:row; default, not needed */ flex-wrap: wrap; margin-left: -10px; /* compensate for item margin */}
.wrapper div { min-width: 300px; background: lightblue; border: 1px solid blue; flex-grow: 1; padding: 10px; margin-left: 10px; /* added left margin */}
<div class="container"> <div class="wrapper"> <div>one</div> <div>two</div> <div>three</div> <div>four</div> <div>five</div> </div></div>
Related Topics
Special Character Not Displaying as Expected
How Much Faster Is It to Use Inline/Base64 Images for a Web Site Than Just Linking to The Hard File
How to Load JavaScript Code Using <Link> Tag
Angular4 - Scrolling to Anchor
Schema.Org/Microdata Markup for List of Recent Posts Without Providing "Author"/"Publisher"
How to Use Custom Fonts in an HTML5 Canvas Element
How (And Why) to Use Display: Table-Cell (CSS)
How to Make a HTML Page to Show Content from Another Url
How to Use <Section> and <Article> Tags in HTML5
Body { Overflow-X: Hidden; } Breaks Position: Sticky
How to Detect HTML5 Audio Mp3 Support
CSS Calc Viewport Units Workaround
Fast and Responsive Interactive Charts/Graphs: Svg, Canvas, Other
How to Stretch a Background Image to Cover The Entire HTML Element