How to make a flexible 2x3 grid using flexbox - html

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>

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>

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>

Flexbox item wrap to a new line [duplicate]

This question already has answers here:
How to specify line breaks in a multi-line flexbox layout?
(9 answers)
Closed 5 years ago.
There is a flexbox grid.
.flex {
display: flex;
flex-wrap: wrap;
border: 2px solid red;
}
.item {
width: 50px;
height: 50px;
margin: 5px;
border: 2px solid blue;
}
<div class="flex">
<div class="item"></div>
<div class="item"></div>
<div class="item new-string"></div>
</div>
How to transfer .new-string to a new line, along with the elements that follow it?
If you look at this great answer you'll notice that the only cross-browser way (without 2 line break limit) is inserting 100%-width empty blocks ("line-breaks"). So for similar markup this will look like
.flex {
display: flex;
flex-wrap: wrap;
border: 2px solid red;
}
.item {
width: 50px;
height: 50px;
margin: 5px;
border: 2px solid blue;
}
.line-break {
width: 100%;
}
<div class="flex">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="line-break"></div>
<div class="item"></div>
<div class="item"></div>
<div class="line-break"></div>
<div class="item"></div>
<div class="line-break"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
If you want to preserve your markup style, you'll have to insert this line-break blocks via JavaScript:
var items = document.querySelectorAll(".flex > .item.new-string");
for (var i = 0; i < items.length; i++) {
var lineBreak = document.createElement('div');
lineBreak.className = "line-break";
items[i].parentNode.insertBefore(lineBreak, items[i]);
}
.flex {
display: flex;
flex-wrap: wrap;
border: 2px solid red;
}
.item {
width: 50px;
height: 50px;
margin: 5px;
border: 2px solid blue;
}
.line-break {
width: 100%;
}
<div class="flex">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item new-string"></div>
<div class="item"></div>
<div class="item new-string"></div>
<div class="item new-string"></div>
<div class="item"></div>
<div class="item"></div>
</div>
This seems to be possible to do with Grid-layout.
First to position items inline you can use
grid-template-columns: repeat(auto-fill, 50px);
so that each item takes 50px and it will position items in one line until no more items can fit in one line. And then you can use grid-column-start: 1; on specific item so that it goes to new line.
* {
box-sizing: border-box;
}
.flex {
display: grid;
grid-gap: 10px;
grid-template-columns: repeat(auto-fill, 50px);
border: 2px solid red;
}
.item {
width: 50px;
height: 50px;
margin: 5px;
border: 2px solid blue;
}
.new-string {
grid-column-start: 1;
background: red;
}
<div class="flex"><div class="item"></div><div class="item"></div><div class="item"></div><div class="item new-string"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item new-string"></div><div class="item"></div><div class="item"></div><div class="item new-string"></div><div class="item"></div></div>
As an alternative you could simply do this
HTML
<div class="flex">
<div class="item"></div>
<div class="item"></div>
<div class="item line-break"></div>
<div class="item new-string"></div>
</div>
CSS
.line-break {
width: 100%;
}
The 100% width flex item will give you the line break.
Easiest way to get a new line in the flex grid, sure you need an extra div but I don't find it that bad of a way to do it
All flex items are set by default to order: 0. This means they will be laid out in the order they appear in the source code.
If you give the last item order: 1, this forces it to be last when additional items are added.
The ::before and ::after pseudo elements on a flex container create new flex items.
So if we add one pseudo element with a large enough width, it will force your last item (set by order) to the next row.
.flex {
display: flex;
flex-wrap: wrap;
border: 2px solid red;
}
.item {
width: 50px;
height: 50px;
margin: 5px;
border: 2px solid blue;
}
.new-string {
order: 1;
}
.flex::after {
content: "";
flex: 0 0 100%;
height: 0;
}
<div class="flex">
<div class="item"></div>
<div class="item"></div>
<div class="item new-string"></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>

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