How to get items break to next row if they exceeds to 3 columns with flexbox css - html

I'm trying to loop an array of objects and display them in grid view but with the flexbox concept in CSS.
<div class="container">
<div class="innercontainer">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4 (to go to row 2 if there is 4)</div>
</div>
</div>
.container {
width: 100%;
background-color: red;
}
.innercontainer {
display: flex;
gap: 5px;
flex-wrap: wrap;
}
.item {
flex: 1;
background-color: yellow;
padding: 30px;
}
The above code works perfectly fine until 3 items. When 4th item comes, I want it to go to the next row.
I tried some research and did this but not working.
<div class="container">
<div class="innercontainer">
<div class="item">1</div>
<div class="breaker"></div>
<div class="item">2</div>
<div class="breaker"></div>
<div class="item">3</div>
<div class="breaker"></div>
<div class="item">4 (to go to row 2 if there is 4)</div>
<div class="breaker"></div>
</div>
</div>
I appended this css code to above css, but not working.
.breaker {
display: none;
}
.breaker:nth-child(3n) {
display: block;
width: 100%;
height: 0;
}
You can see them in codepen. (https://codepen.io/apple-hhh/pen/bGMMByr)
What I want is:
With my first implementation, I have achieved the first 2 scenarios from the picture.

Use CSS grid for this:
.container {
display: grid;
grid-auto-flow: column;
gap: 5px;
border: 1px solid;
margin: 20px 0;
}
.container > div:nth-child(3n + 1) {grid-column: 1}
.container > div:nth-child(3n + 2) {grid-column: 2}
.container > div:nth-child(3n + 3) {grid-column: 3}
.container > div {
height: 50px;
background: red;
}
<div class="container">
<div></div>
</div>
<div class="container">
<div></div>
<div></div>
</div>
<div class="container">
<div></div>
<div></div>
<div></div>
</div>
<div class="container">
<div></div>
<div></div>
<div></div>
<div></div>
</div>

Try adding flex-basis: 25%; to your .item class. Usually, 33% would work but since you have padding in the item class, you might have to play around with it a bit.
flex-basis: https://developer.mozilla.org/en-US/docs/Web/CSS/flex-basis
In my experience using grid instead of flex is better here.

.item{
background-color: yellow;
width: 33%;
flex-grow: 1;
}

Related

CSS selector for grouping elements by 2 and 3 per row [duplicate]

This question already has answers here:
How to select a range of elements in repeated pattern
(2 answers)
Closed 1 year ago.
I have a list of elements I want to style 2 and 3 per row alternatively. Ideally I want a CSS solution.
Regardless of using float, flex, or grid, there is still the issue of the CSS selector.
I was initially thinking of using something like :nth-child(n+3) and :nth-child(n+2) but that made no sense.
This is the style I'm using right now, but I'm looking for a more dynamic solution.
.parent {
display: flex;
flex-wrap: wrap;
}
.element {
display: flex;
justify-content: center;
margin-bottom: 50px;
width: 50px;
height: 50px;
}
.element > div {
background-color: black;
width: 100px;
}
.element:nth-child(1),
.element:nth-child(2) {
width: 50%;
}
.element:nth-child(3),
.element:nth-child(4),
.element:nth-child(5) {
width: 33%;
}
.element:nth-child(6),
.element:nth-child(7) {
width: 50%;
}
<div class="parent">
<div class="element">
<div></div>
</div>
<div class="element">
<div></div>
</div>
<div class="element">
<div></div>
</div>
<div class="element">
<div></div>
</div>
<div class="element">
<div></div>
</div>
<div class="element">
<div></div>
</div>
<div class="element">
<div></div>
</div>
</div>
Here's a fiddle, this might be what you're looking for
https://jsfiddle.net/xch0m5zy/
.box:nth-child(-n+3) {
background-color: blue;
}
.box:nth-child(n+4) {
background-color: red;
}
.box:nth-child(n+7) {
background-color: green;
}

css - using grid-auto-column to create dynamic widths

I'm trying to get my css grid to either be 2 blocks per row (if there are enough items) or a single block that spans the entire width. However, I can't seem to get it to work using grid-auto-column.
The top block is what I want it to look like, and the bottom block is what my current css is creating.
.flex1 {
display: flex;
flex-direction: row;
flex: 1;
}
.grid1 {
display: grid;
grid-auto-columns: minmax(50%, 100%);
}
div.height {
height: 50px;
width: 100%;
}
.red {
background-color: red;
}
.blue {
background-color: blue;
}
.green {
background-color: green;
}
<div class="flex1">
<div class="red height">
</div>
<div class="blue height">
</div>
</div>
<div>
<div class="green height">
</div>
</div>
<br><br>
<div class="grid">
<div class="red height">
</div>
<div class="blue height">
</div>
<div class="green height">
</div>
</div>
Unfortunately, as far as I know, this isn't possible with the Grid, but it's a perfect and easy job for Flexbox, since you only need to handle one or single dimensional layout, in your case rows.
Below I'm giving you the shorter version of the desired result / behavior of flex-items, with less markup and styling:
.flex {
display: flex;
flex-wrap: wrap; /* enables wrapping of flex-items */
}
.flex > div {
flex: 1 0 50%; /* grows full width if alone in a row / doesn't shrink / initial width set to 50%, i.e. can't be less than 50% of the parent's width */
height: 50px;
}
.red {background: red}
.blue {background: blue}
.green {background: green}
.yellow {background: yellow}
<div class="flex">
<div class="red"></div>
</div>
<br>
<div class="flex">
<div class="red"></div>
<div class="blue"></div>
</div>
<br>
<div class="flex">
<div class="red"></div>
<div class="blue"></div>
<div class="green"></div>
</div>
<br>
<div class="flex">
<div class="red"></div>
<div class="blue"></div>
<div class="green"></div>
<div class="yellow"></div>
</div>
Use grid-template-areas: "a b" "c c";(change .grid1 to .grid as in html)
Also set grid-area:; to each div inside .grid
.flex1 {
display: flex;
flex-direction: row;
flex: 1;
}
.grid {
display: grid;
grid-auto-columns: minmax(50%, 100%);
grid-template-areas: "a b" "c c";
}
div.height {
height: 50px;
width: 100%;
}
.red {
background-color: red;
}
.blue {
background-color: blue;
}
.green {
background-color: green;
}
<div class="flex1">
<div class="red height">
</div>
<div class="blue height">
</div>
</div>
<div>
<div class="green height">
</div>
</div>
<br><br>
<div class="grid">
<div class="red height" style="grid-area: a;">
</div>
<div class="blue height" style="grid-area: b;">
</div>
<div class="green height" style="grid-area: c;">
</div>
</div>

Layout a flex box similar to a table?

I'm working with a framework developed in-house which depends on a certain structure to our HTML. And one of the tricky things is that each row needs its own container with its own classes and data attributes.
So here's the problem. Without drastically changing the DOM, how can I make the flex box below render essentially like an HTML table would? Or is a table the only way? The solution will have to work in both IE11 and Chrome.
I'm trying to make it look like this...
Column A | Column B | Column C
1 | 2 | 3
section {
display: flex;
flex-wrap: wrap;
}
section .col {
flex: 1 1 auto;
}
section .line-break {
flex-basis: 100%;
width: 0px;
height: 0px;
overflow: hidden;
}
<html>
<head>
</head>
<body>
<section>
<header>
<div class="col">Column A</div>
<div class="col">Column B</div>
<div class="col">Column C</div>
</header>
<div class="line-break"></div>
<div class="row">
<div class="col">1</div>
<div class="col">2</div>
<div class="col">3</div>
</div>
</section>
</body>
</html>
header, .row {
display: flex; /* aligns all child elements (flex items) in a row */
}
.col {
flex: 1; /* distributes space on the line equally among items */
}
<section>
<header>
<div class="col">Column A</div>
<div class="col">Column B</div>
<div class="col">Column C</div>
</header>
<div class="row">
<div class="col">1</div>
<div class="col">2</div>
<div class="col">3</div>
</div>
</section>
If the content you are going to present is of type tabular data, then a table is the proper way.
HTML 5.1 W3C Recommendation, 1 November 2016, 4.9 Tabular data
Given that you can't, or don't want to, alter the markup, this can be done using CSS Table, and with that easily swap between any display type such as flex, block, etc., or even float, using media query etc.
I also removed the <div class="line-break"></div> element, since you don't need, though if it is rendered by a component or similar, leaving it as is won't cause any problem.
Using CSS Table
section {
display: table;
width: 100%;
}
section > * {
display: table-row;
}
section .col {
display: table-cell;
}
<html>
<head>
</head>
<body>
<section>
<header>
<div class="col">Column A</div>
<div class="col">Column B</div>
<div class="col">Column C</div>
</header>
<div class="row">
<div class="col">1</div>
<div class="col">2</div>
<div class="col">3</div>
</div>
</section>
</body>
</html>
If you still need, or have to, use Flexbox, this answer of mine mention the difference between CSS Table and Flexbox on two important features:
Can flexbox handle varying sizes of columns but consistent row height?
Updated, a sample showing some useful Flexbox stuff, with varying width's and span columns.
Using Flexbox
.tbl {
display: flex;
flex-direction: column;
}
.row {
display: flex;
min-height: 50px;
}
.cell {
flex: 4;
border: 1px solid red;
}
.cell:nth-child(1) {
flex: 1;
}
.cell:nth-child(2) {
flex: 2;
}
.cell.span4-5 {
flex: 8 24px; /* col 4,5 flex-grow/border/padding */
}
.cell.span3-4 {
flex: 8 24px; /* col 3,4 flex-grow/border/padding */
}
.cell.span3-5 {
flex: 12 36px; /* col 3,4,5 flex-grow/border/padding */
}
.row:first-child .cell {
display: flex;
justify-content: center; /* center horiz. */
align-items: center; /* center vert. */
}
.row .cell {
padding: 5px;
box-sizing: border-box;
}
<div class="tbl">
<div class="row">
<div class="cell">ID </div>
<div class="cell">Nr </div>
<div class="cell">Header 1 </div>
<div class="cell span4-5"> Header 2 </div>
</div>
<div class="row">
<div class="cell">1</div>
<div class="cell">2</div>
<div class="cell">Content</div>
<div class="cell">Content</div>
<div class="cell">Content</div>
</div>
<div class="row">
<div class="cell">2</div>
<div class="cell">3</div>
<div class="cell span3-5">Content</div>
</div>
<div class="row">
<div class="cell">1</div>
<div class="cell">2</div>
<div class="cell span3-4">Content</div>
<div class="cell">Content</div>
</div>
</div>
This code works for me:
* {
box-sizing: border-box;
}
body, html {
height: 100%;
margin: 0;
}
#container {
width: 400px;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: flex-start;
background-color: lightgrey;
padding: 10px;
}
.shelf {
flex: 1 1 auto;
width: 100%;
margin-bottom: 10px;
border: 1px solid black;
background-color: lightgreen;
display: flex;
flex-direction: row;
}
.shelf:last-child {
margin-bottom: 0;
}
.labelbox {
flex: 0 0 35%;
}
.valuebox {
flex: 0 0 65%;
}
<div id="container">
<div class="shelf">
<div class="labelbox">Name: </div> <div class="valuebox">Barry Carter</div>
</div>
<div class="shelf">
<div class="labelbox">DOB:</div><div class="valuebox">10/12/1980</div>
</div>
<div class="shelf">
<div class="labelbox">
Description:
</div>
<div class="valuebox">
This content goes on and on and will force the height to expand. And the label box to the left will
"move" with it. There need not be much of a relation other than that their parent div/flex-container is
getting taller as well.
</div>
</div>
<div class="shelf">
<div class="labelbox">Group:</div><div class="valuebox">Advanced</div>
</div>
<div class="shelf">
<div class="labelbox">End Date:</div><div class="valuebox">2020-09-20</div>
</div>
</div>
Use CSS Grid. You can style any table the way you like.
Keep in mind If your table is more than 700 rows, the fram rate will start to drop, no matter what js framework you use. react, angular, vue or vanila JS. the scrolling will get real laggy.
And the maximum you row can use is 1000. More than that the extra row will create bad graphic. But you wont reach 1000 anyway, because at 700th row, the scrolling speed, starts to get bad.
If somehow you need to display more than 1000 rows, you will visualized lib. Every js framework has a lib to do so. Basically, it will render the rows in the view port. The rows that not in the view port will not be rendered. They will only be rendered when user scrolls.
This is year 2021, chances you read this answer in the future, the browsers vendor might probably fix the performance of 1000 rows, they might even extend that limit. So try it out.

How can I get even heights of unknown elements inside a column? [duplicate]

This question already has answers here:
Equal height flex items in flex columns
(3 answers)
Closed 5 years ago.
I'm using flex to create even columns and vh to make them the same height. That's working fine but inside the columns I can have an x number of items in them. I'd like for elements in each column to be even height depending on how many items are present (using css).
1 = 100%
2 = 50%
3 = 33.33%
etc.
I know I can do this through JS but I'd like to automate this through css via flex, grid, or something elese.
I've tried replicating your problem. Use flex: 1 on .items so that each and every item take equal space (according to the problem statement).
Have a look at the snippet below:
body {
margin: 0;
}
.parent {
width: 80%;
padding: 20px;
display: flex;
border: 1px solid red;
}
.child {
flex: 1;
display: flex;
flex-direction: column;
align-items: stretch;
justify-content: flex-end;
padding: 20px;
border: 1px solid blue;
height: 60vh;
}
.item {
flex: 1;
background: lightGreen;
border: 1px solid green;
}
<div class="parent">
<div class="child">
<div class="item">33.33%</div>
<div class="item">33.33%</div>
<div class="item">33.33%</div>
</div>
<div class="child">
<div class="item">50%</div>
<div class="item">50%</div>
</div>
<div class="child">
<div class="item">100%</div>
</div>
</div>
Hope this is what you are trying to achieve.
This is all you need to make it work with the Flexbox:
.flex-container {
display: flex;
}
.flex-item {
display: flex;
flex-direction: column;
flex: 1;
}
.item {
flex: 1;
border: 1px solid;
}
<div class="flex-container">
<div class="flex-item">
<div class="item">1/1</div>
</div>
<div class="flex-item">
<div class="item">1/2</div>
<div class="item">1/2</div>
</div>
<div class="flex-item">
<div class="item">1/3</div>
<div class="item">1/3</div>
<div class="item">1/3</div>
</div>
<div class="flex-item">
<div class="item">1/4</div>
<div class="item">1/4</div>
<div class="item">1/4</div>
<div class="item">1/4</div>
</div>
</div>

A two-column card-based layout for desktop and mobile using flexbox

I want to make a two column html structure like the following picture:
The numbers inside each box means the order of the div's in the html markup.
The challenge is that I want to have a different sort order on a mobile device. For example, on a mobile device, number 4 should be below number 1 without changing the html. I think using flexbox should be the best way to achieve this. But I couldn't make it work.
Using floats isn't the way, because at the first side when there is some space, the next div will automatic float to that side.
I also cannot make extra wrapper's for each column, because using order will not work then.
Does somebody has an idea?
* {
box-sizing: border-box;
}
.row {
display: inline-block;
width: 100%;
}
.item {
border: 1px solid #000;
width: 50%;
float: left;
}
<div class="row">
<div style="height:200px;" class="item">1</div>
<div style="height:150px;" class="item">2</div>
<div style="height:100px;" class="item">3</div>
<div style="height:50px; float:right;" class="item">4</div>
<div style="height:75px; float:right;" class="item">5</div>
<div style="height:150px; float:right;" class="item">6</div>
</div>
The code below features:
A column-direction flex container
Flex items wrap at viewport height
On smaller screens (based on height or width), the fourth item moves to the second position in the visual order, and the items align in a single full-width column.
* {
box-sizing: border-box;
}
.row {
display: flex;
flex-direction: column;
flex-wrap: wrap;
height: 100vh;
max-width: 100vw;
}
.item {
width: 45%;
margin: 5px;
border: 1px solid #000;
}
#media ( max-width: 500px ), ( max-height: 500px ) {
.row { flex-direction: row; }
.item { flex-basis: 100%; }
.item:nth-child(1) { order: -2; }
.item:nth-child(4) { order: -1; }
}
<div class="row">
<div style="height:200px;" class="item">1</div>
<div style="height:150px;" class="item">2</div>
<div style="height:100px;" class="item">3</div>
<div style="height:50px;" class="item">4</div>
<div style="height:75px;" class="item">5</div>
<div style="height:150px;" class="item">6</div>
</div>
jsFiddle