5 items per row, auto-resize items in flexbox - html

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%;
}

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 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>

Wrap items for last row in flex layout with space between alignment

Is there any way to have wraped items in rows with space between alignment, where last row dont have big gap?
<div fxFlex="row wrap" fxLayoutAlign="space-around">
<my-item *ngFor="let item of items"></my-item>
</div>
Actual behaviour:
I need same "space-between" in last row compared to other rows.
The quickest way to get what you're looking for is to add an empty element after the last visible element:
<!-- your last 3 boxes -->
<div class="gray-box">
(your content)
</div>
<div class="gray-box">
(your content)
</div>
<div class="gray-box">
(your content)
</div>
<!-- an empty box - make sure .transparent has opacity: 0-->
<div class="gray-box transparent"></div>
If you're okay with not using flexbox, display: grid is more along the lines of what you're looking for, where you can define grid sizes more strictly:
display: grid;
grid-template-columns: repeat(4, 25%);
grid-gap: /* gap between your items */
You can use "filler" elements. You need 3 elements at the end of your list which are no visible. Everytime when your row breaks the filler helping to keep the right sizes and spaces.
const addbutton = document.getElementsByClassName('add');
// referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
const addEl = () => {
const newli = document.createElement('li');
newli.textContent = 'new flex child';
const pos = document.querySelector('li.filler');
pos.parentNode.insertBefore(newli, pos.previousElementSibling.nextSibling);
}
addbutton[0].addEventListener('click', addEl);
body {
display: flex;
}
ul {
display: flex;
flex-flow: row wrap;
justify-content: space-between;
padding: 0;
flex: 1;
}
ul>li {
flex: 0 1 24%;
background: #ccc;
display: block;
height: 40px;
margin-bottom: 20px;
}
ul>li.filler {
height: 0;
padding: 0;
}
button {
background: #333;
color: white;
border: none;
padding: 5px;
flex: 0 0 100px;
height: 100px;
margin: 10px;
}
<button class="add">click here to add childs</button>
<ul>
<li>lorem</li>
<li>lorem</li>
<li>lorem</li>
<li>lorem</li>
<li>lorem</li>
<li>lorem</li>
<li class="filler"></li>
<li class="filler"></li>
<li class="filler"></li>
</ul>
I'm just guessing on your html and css structure here, but I assume you have something like this:
.wrapper {
width: 1000px;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.item {
background: gray;
width: 200px;
height: 100px;
border: 1px solid black;
}
<div class="wrapper">
<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>
You can keep the same spacing around each element by using a simple margin and setting the justify-content attribute to either center or flex-start based on your needs.
.wrapper {
width: 1000px;
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
}
.item {
background: gray;
width: 200px;
height: 100px;
border: 1px solid black;
margin: 0 20px;
}
<div class="wrapper">
<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>

margins and flex-wrap in a flexbox

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>

How to make orphan item in a wrapping flex grid not grow to fill the last row? [duplicate]

This question already has answers here:
Targeting flex items on the last or specific row
(10 answers)
Closed 5 years ago.
I need a grid where I only specify the minimum width of the items.
Here is my attempt using flex-wrap and flex-basis: https://jsfiddle.net/2z9pgjfg/1/
HTML:
<div class="container">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
CSS:
.container {
display: flex;
flex-wrap: wrap;
}
.item {
background-color: red;
border: 1px solid black;
flex: 1;
flex-basis: 150px;
}
.item:after {
content: "";
display: block;
padding-bottom: 75%;
}
I want any items in the last row to be the same size as all the others. Is there a way to achieve this without media queries?
Set flex grow to 0.
.container {
display: flex;
flex-wrap: wrap;
}
.item {
background-color: red;
border: 1px solid black;
flex: 0;
flex-basis: 150px;
}
.item:after {
content: "";
display: block;
padding-bottom: 75%;
}
<div class="container">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>