margins and flex-wrap in a flexbox - html

I have a problem with flex-wrap property of a flexbox.
Here is my code:
.container {
display: flex;
flex-wrap: wrap;
}
.item {
width: 50%;
margin: 0 10px;
}
<div class="container">
<div class="item"></div>
<div class="item"></div>
</div>
What I want to do is to let some space margin between items but without wrapping them. I want them horizontally two by two and every item with width of 50% margin included to prevent flex-wrap.

.container {
display: flex;
flex-wrap: wrap;
}
.item {
flex: 1 0 34%; /* fg, fs, fb */
margin: 10px;
height: 50px;
background-color: gray;
}
<div class="container">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
With flex-grow: 1 defined in the flex shorthand, there's no need for flex-basis (width) to be 50%, which results in one item per row due to the margins.
Since flex-grow will consume free space on the row, flex-basis only needs to be large enough to enforce a wrap.
In this case, with flex-basis: 34%, there's plenty of space for the margins, but not enough space for a third item on each line.

You can use calc for this, so for example you can set flex-basis: calc(50% - margin x 2).
.container {
display: flex;
flex-wrap: wrap;
}
.item {
flex-basis: calc(50% - 20px);
margin: 10px;
background: lightblue;
height: 50px;
}
<div class="container">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>

You may use calc to exclude margin from the width:
.container {
display: flex;
flex-wrap: wrap;
}
.item {
width: calc(50% - 20px);
margin: 5px 10px;
height:20px;
background:red;
}
<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>

Related

How to set 3 items in row FLEXBOX [duplicate]

This question already has answers here:
How to add 1px margin to a flex item that is flex: 0 0 25%?
(4 answers)
Closed 9 months ago.
I would like to display 3 items per row, but I want to include margin and border.
Here's is a simple example, but I need to set valid flex property
.box {
display: flex;
flex-wrap: wrap;
width: 1200px;
}
.item {
display: flex;
border: 1px solid #000;
margin: 5px;
flex: // ???
}
<div class="box">
<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>
As far as I understood your question.
Instead of margin use gap property
.box {
width: 100%;
display: flex;
flex-wrap: wrap;
gap: 1rem;
}
.item {
flex: 1;
width: 100%;
height: 200px;
border: 1px solid #000;
}
.item:nth-child(4),
.item:nth-child(5),
.item:nth-child(6) {
flex: 0 1 100%;
}
<div class="box">
<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>
I would probably do it like this:
Seeing as you have specified a fixed width-value, you could just make each item have a max-width of 400px - border and margin. However, for a more dynamic layout, you could just use max-width: 1200px on box, so its resizable and responsive.
I prefer to use gap instead of margin in flex-layouts. With this, you can set each items max-width to 33.33% (for a 3 row layout), minus the 5px gap and the 1px border. Also, you don't have to use display: flex on the items, as they are already children of a flex-container (unless you plan to have more content inside them).
This would produce this:
.box {
display: flex;
flex-wrap: wrap;
max-width: 1200px;
flex: 1; /* equal items */
gap: 5px;
}
.item {
border: 1px solid #000;
width: 100%;
max-width: calc(33.33% - 6px);
}
<div class="box">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
<div class="item">5</div>
<div class="item">6</div>
</div>
However, this is also achievable by using margin and a fixed width. Then you just have to use the items margin and border in the max-width calculation (5px + 5px + 1px + 1px). Keep in mind when using margin in the layout, its also going to affect the margin between the container and the items - not just the gap between the items.
.box {
display: flex;
flex-wrap: wrap;
width: 1200px;
flex: 1; /* equal items */
}
.item {
border: 1px solid #000;
height: 20px;
margin: 5px;
width: 100%;
max-width: calc(33.33% - 12px);
}
<div class="box">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
<div class="item">5</div>
<div class="item">6</div>
</div>
I rather use flex-basis on child.
.box {
display: flex;
flex-wrap: wrap;
width: 1200px;
}
.item {
display: flex;
border: 1px solid #000;
margin: 5px;
flex-basis: 30%
}
<div class="box">
<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>

How can I adjust the space-between not splitting its last two items in a 3-col situation? [duplicate]

This question already has answers here:
Targeting flex items on the last or specific row
(10 answers)
Closed 1 year ago.
The last row, there are only two blocks and they got split on the left and right.
Is it possible to let they just aligned normally?
#wrap {
width: 500px;
display:flex;
flex-wrap: wrap;
justify-content: space-between;
}
.item {
background: red;
width: 32%;
height: 20px;
margin-top:9px;
}
<div id="wrap">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
Dont use justify-content: space-between; but add the margin yourself:
#wrap {
width: 500px;
display: flex;
flex-wrap: wrap;
}
.item {
background: red;
width: 32%;
height: 20px;
margin-top: 9px;
}
.item+.item {
margin-left: 2%;
}
.item:nth-child(3n+1) {
margin-left: 0;
}
<div id="wrap">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>

Orphaned Inline Divs

I have a series of inline-block divs that can wrap onto a second line depending on how wide the browser is at a given time. Here's a fiddle example. For example, it might look like this:
However if the viewport is of a certain width, it can end up with just one orphaned inline-block on the next line:
Is there a CSS method that is essentially some form of "orphan control" (CSS orphan doesn't seem to apply in this situation) so that if there are fewer than a certain number of elements on the second line, it'd wrap more of them down there to even things out?
.container {
width: 100%;
}
.item {
display: inline-block;
width: 50px;
background-color: blue;
}
<div class="container">
<div class="item">
Item 1
</div>
<div class="item">
Item 2
</div>
<div class="item">
Item 3
</div>
<div class="item">
Item 4
</div>
<div class="item">
Item 5
</div>
<div class="item">
Item 6
</div>
<div class="item">
Item 7
</div>
</div>
Here is an idea using CSS grid where the trick is to make sure your div has a width expressed as a multiple of a fixed amount to make sure you never have an orphan element.
.wrapper {
--w: 100px; /* width of one item */
display: grid;
grid-template-columns: repeat(auto-fit, calc(2*var(--w))); /* the item will break two by two*/
justify-content:center;
}
.container {
grid-column: 1/-1;
display:flex;
flex-wrap:wrap;
justify-content:center;
}
.item {
width: calc(var(--w) - 10px);
margin: 5px;
}
/* irrelevant styles */
.container {
counter-reset: num;
}
.item {
height: 150px;
background-color: blue;
color: #fff;
}
.item::before {
color: #fff;
content: attr(class) " " counter(num);
counter-increment: num;
}
<div class="wrapper">
<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 class="item"></div>
<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 class="item"></div>
</div>
</div>
If we use 3
.wrapper {
--w: 100px; /* width of one item */
display: grid;
grid-template-columns: repeat(auto-fit, calc(3*var(--w)));
justify-content:center;
}
.container {
grid-column: 1/-1;
display:flex;
flex-wrap:wrap;
justify-content:center;
}
.item {
width: calc(var(--w) - 10px);
margin: 5px;
}
/* irrelevant styles */
.container {
counter-reset: num;
}
.item {
height: 150px;
background-color: blue;
color: #fff;
}
.item::before {
color: #fff;
content: attr(class) " " counter(num);
counter-increment: num;
}
<div class="wrapper">
<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 class="item"></div>
<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 class="item"></div>
</div>
</div>
You could use flex and flex-wrap for this with break points so you can decide how many items are in the top row on each width. Where it is inevitable that there is a single item on the last row this snippet goes for minimising the number of rows.
It would have been nice to use CSS variables for all of this so the choice is easily altered, but you can't use variables in media queries so we have to put them in by hand.
.container {
width: 104px; /* item width plus 2 lots of padding */
margin: 0;
padding: 0;
justify-content: center;
display: flex;
flex-wrap: wrap;
}
#media (min-width: 312px) {
.container {
width: 312px;
}
}
#media (min-width: 416px) {
.container {
width: 416px;
}
}
#media (min-width: 728px) {
.container {
width: 728px;
}
}
.item {
r-sizing: border-box;
width: 100px;
background-color: cyan;
text-align: center;
flex: 0 0 100px; /* made 100px so easier to test on different widthe */
margin: 2px;
}
<div class="container">
<div class="item">
Item 1
</div>
<div class="item">
Item 2
</div>
<div class="item">
Item 3
</div>
<div class="item">
Item 4
</div>
<div class="item">
Item 5
</div>
<div class="item">
Item 6
</div>
<div class="item">
Item 7
</div>
</div>

How to make a flexible 2x3 grid using flexbox

I'm trying to create a HTML page that has 3 rows of 2 cells in each. I want all 6 cells to fill the entire page equally without having to specify a height so that when the browser is re-sized, so to are the cells.
I am trying to use the following flex layout but I'm getting them all in a row.
.outer {
display: flex;
min-height: 100%;
}
.row {
border: 1px solid blue;
display: flex;
flex: 1.0;
flex-grow: 1.0;
}
.item {
background-color: orange;
flex: .5;
flex-grow: 0.5;
border: 1px solid red;
}
<div class="outer">
<div class="row">
<div class="item"></div>
<div class="item"></div>
</div>
<div class="row">
<div class="item"></div>
<div class="item"></div>
</div>
</div>
Make the outer wrapper a column flexbox:
add flex: 1 to each row so that the rows share the vertical space,
add flex: 1 to each item so that the columns share the horizontal space,
finished up with height: 100% on both body and html elements (you can also use viewport height to set the min-height) and setting default body margin to zero.
See demo below:
body, html {
margin: 0;
height: 100%;
}
.outer {
display: flex;
min-height: 100%;
flex-direction: column; /* added */
}
.row {
border: 1px solid blue;
display: flex;
flex: 1; /* added */
}
.item {
background-color: orange;
border: 1px solid red;
flex: 1; /* added */
}
<div class="outer">
<div class="row">
<div class="item"></div>
<div class="item"></div>
</div>
<div class="row">
<div class="item"></div>
<div class="item"></div>
</div>
<div class="row">
<div class="item"></div>
<div class="item"></div>
</div>
</div>

5 items per row, auto-resize items in flexbox

I have this at the moment:
.container {
background: gray;
width: 600px;
display: flex;
flex-flow: row wrap;
position: relative;
}
.item {
background: blue;
width: auto;
height: auto;
margin: 4px;
flex: 1;
flex-basis: 20%;
}
<div class="container">
<div class="item">A</div>
<div class="item">B</div>
<div class="item">C</div>
<div class="item">D</div>
<div class="item">E</div>
<div class="item">F</div>
<div class="item">G</div>
</div>
What I'm trying to do is have 5 items per row in a flexbox. Currently they don't appear because they don't have a set width/height, which leads me to my next question. Is it possible to auto-resize the items in order for 5 of them to fit per row?
How would I do this?
Thanks!
You are right in giving a flex-basis: 20% but you have to adjust for the 4px margin on each flex item for it to wrap properly.
Equal Width Flex items in the last row
Use flex: 0 1 calc(20% - 8px) - this means the item won't grow beyond 20% of width (adjusting for margin) and can shrink based on the container width. See demo below:
.container {
background: gray;
width: 600px;
height: 200px; /* height given for illustration */
display: flex;
flex-flow: row wrap;
position: relative;
}
.item {
background: blue;
margin: 4px;
flex: 0 1 calc(20% - 8px); /* <-- adjusting for margin */
}
<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 class="item"></div>
</div>
Another approach is a bit hacky - you can keep flex-grow set to one and flex-basis: calc(20% - 4px) using flex: 1 1 calc(20% - 4px), and use a pseudo element that fills the remaining space:
.container {
background: gray;
width: 600px;
height: 200px; /* height given for illustration */
display: flex;
flex-flow: row wrap;
position: relative;
}
.item {
background: blue;
margin: 4px;
flex: 1 1 calc(20% - 8px); /* <-- adjusting for margin */
}
.container:after {
content: '';
display: block;
flex: 999; /* grow by a large number */
}
<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 class="item"></div>
</div>
If you don't have the n item per row requirement then you can refer this:
Unordered list that acts like grid-auto-flow dense
Flex items in last row expands to fill the available space
If in a row you have less than 5 items and you want them to fill in the remaining space use flex: 1 1 calc(20% - 8px) (note that flex-grow is set to 1 here so that the flex items in the last rows expand to fill the remaining space):
.container {
background: gray;
width: 600px;
height: 200px; /* height given for illustration */
display: flex;
flex-flow: row wrap;
position: relative;
}
.item {
background: blue;
margin: 4px;
flex: 1 1 calc(20% - 8px); /* <-- adjusting for margin */
}
<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 class="item"></div>
</div>
try below css for five items in each row.
.container {
background: gray none repeat scroll 0 0;
display: flex;
flex-flow: row wrap;
position: relative;
width: auto;
}
.item {
background: blue none repeat scroll 0 0;
flex: 1 1 18%;
height: auto;
margin: 4px;
padding: 20px 0;
width: auto;
}
<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 class="item"></div>
</div>
I'm using this on a WordPress project, where I have to list articles by categories, nested in columns. I just wrote some css for the responsive layout, so as you decrease the browser width, there are less elements in a row.
.container {
margin: 20px auto;
width: 80%;
min-height: 100px;
display: flex;
flex-flow: row wrap;
}
.item {
margin: 10px;
flex: 1 1 calc(20% - 20px);
background-color: lightgreen;
}
#media screen and (max-width: 1200px) {
.item {
flex: 1 1 calc(25% - 20px)
}
}
#media screen and (max-width: 900px) {
.item {
flex: 1 1 calc(33% - 20px)
}
}
#media screen and (max-width: 750px) {
.item {
flex: 1 1 calc(50% - 20px)
}
}
#media screen and (max-width: 550px) {
.item {
flex: 1 1 calc(100% - 20px)
}
}
<div class="container">
<div class="item"><a>Link1</a></div>
<div class="item"><a>Link1</a></br><a>Link2</a></div>
<div class="item"><a>Link1</a></br><a>Link2</a></br><a>Link3</a></div>
<div class="item"><a>Link1</a></br><a>Link2</a></br><a>Link3</a></br><a>Link4</a></div>
<div class="item"><a>Link1</a></br><a>Link2</a></br><a>Link3</a></br><a>Link4</a></br><a>Link5</a></div>
<div class="item"><a>Link1</a></br><a>Link2</a></br><a>Link3</a></br><a>Link4</a></br><a>Link5</a></br><a>Link6</a></div>
</div>
Here is a possible solution: https://jsfiddle.net/9f955jk2/3/
You have to be aware of margins or paddings, that's why I setted the width to 18%
You can set them to 20% (100%/5 items per row) if you will remove all the margins and paddings.
Also don't forget that border will also take some space.
The container should have 100%, otherwise you have to divide the width by 5 and specify it in pixel for each item and not in %
.container {
width:100%;
}