Nested flex-box wrapping issue [duplicate] - html

This question already has answers here:
The difference between flex:1 and flex-grow:1
(2 answers)
Nested column flexbox inside row flexbox with wrapping
(2 answers)
Closed 5 years ago.
Edit
Unlike The difference between flex:1 and flex-grow:1 . While the answer ultimately was the use of flex instead of flex-grow, my question was not the difference between the two but rather how to get nested flex-boxes to wrap appropriately. For someone struggling with this issue, there would be no way to find that answer on SO without already knowing the issue was the use of flex vs. flex-grow. If I already knew the issue was the difference between flex and flex-grow, I wouldn't have needed to ask the question.
Edit 2
If this post is going to be flagged as duplicate, it would be better to list it as a duplicate of Nested column flexbox inside row flexbox with wrapping instead of The difference between flex:1 and flex-grow:1.
I have a series of div tags that are defined as display:flex. They are laid out as a row with 3 columns. The first two columns are given a width and the third column is allowed to stretch to fill the rest of the space. The row is also set to wrap so that on smaller screens, the third column will wrap below the other two columns.
Here is some basic example code:
style.css
.flex-row {
display: flex;
flex-direction: row;
flex-grow: 1;
}
.flex-column {
display: flex;
flex-direction: column;
flex-grow: 1;
border: 1px solid lightgray;
}
.box {
display: flex;
height: 100px;
width: 300px;
min-width: 200px;
flex-shrink: 1;
border: 1px solid green;
}
index.html
<div class="flex-row" style="flex-wrap:wrap">
<div class="flex-column" style="flex-grow:0">
Column 1
</div>
<div class="flex-column" style="flex-grow:0;width:200px">
Column 2
</div>
<div class="flex-column">
<div class="flex-row" style="min-width:500px;flex-wrap:wrap">
<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>
</div>
</div>
(see my plnk here).
The last column contains a flex row with a series of "boxes" (see the example).
The desired effect is that as the screen is resized, the third column will continue to shrink down to the point where all the boxes are in a single column and the boxes have shrunk to their min-width. At that point, any further reduction in the screen width would cause the third column to wrap below the other two columns and it would then again expand to include as many boxes side by side as possible.
What seems to be happening in practice is that the third column wraps first -- before wrapping the contents it contains.
Here is a visual picture of what I'm want to see happen.
Is this possible to do with flexbox? If so, what am I doing wrong?

Here is what you desire. What you need to change :
For the flex-column it should be flex: 1; instead of flex-grow:1; and set a min-width to it. This way, it can grow and shrink both.
Using flex-grow:1 limits the container to only grow but not shrink and since you're using the flex-column class in the initial container i.e flex-row you need it to be flexible as the viewport is resized.
/* Styles go here */
.flex-row {
display: flex;
flex-direction: flex-row;
flex-grow: 1;
}
.flex-column {
display: flex;
flex-direction: column;
min-width:100px;
flex: 1;
border: 1px solid lightgray;
}
.box {
display:flex;
flex-shrink:1;
border: 1px solid green;
height:100px;
width:300px;
min-width:150px;
}
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css">
<script src="script.js"></script>
</head>
<body>
<div class="flex-row" style="flex-wrap:wrap">
<div class="flex-column" style="flex-grow:0">
Column 1
</div>
<div class="flex-column" style="flex-grow:0;width:200px">
Column 2
</div>
<div class="flex-column">
<div class="flex-row" style="min-width:500px;flex-wrap:wrap">
<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>
</div>
</div>
</body>
</html>

Related

div classes and CSS rows [duplicate]

This question already has answers here:
Flexbox: 4 items per row
(10 answers)
How to display 3 items per row in flexbox?
(3 answers)
Closed last year.
If I have say 6 items within a div and I want to space 3 then 3 directly underneath can I use one div to contain my 6 total divs and space them to wrap under or do I need to have two separate divs to contain 3 in each?
I have tried to use a div to separate at 3 boxes in each div but I cannot get the boxes to line up.
What I am attempting to do is this-
box Box Box
box Box Box
currently it looks like this
box box box box box box
If I
.boxes {
width: 100%;
display: flex;
flex-wrap: wrap;
justify-content: space-evenly;
}
<div class="boxes">
<div class="box1">Box 1</div>
<div class="box2">Box 2</div>
<div class="box3">Box 3</div>
<div class="box4">Box 4</div>
<div class="box5">Box 5</div>
<div class="box6">Box 6</div>
</div>
split the div class=boxes at 3 and create another for the last three boxes it will split into two rows, but I cannot get them to line up. is there a way to wrap around from the code I have written?
Use CSS Grid if you want to set the number of desired columns.
.boxes {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
}
<div class="boxes">
<div class="box1">Box 1</div>
<div class="box2">Box 2</div>
<div class="box3">Box 3</div>
<div class="box4">Box 4</div>
<div class="box5">Box 5</div>
<div class="box6">Box 6</div>
</div>
If you prefer you can also use the CSS repeat() function:
grid-template-columns: repeat(3, 1fr);

Flex child push siblings to the bottom [duplicate]

This question already has answers here:
Force flex item to span full row width
(2 answers)
Closed 1 year ago.
It is posible to have a div parent with display flex and that the first child push the next siblings to the bottom line.
I have this situation and using display flex and the structure can´t be modify.
This could be done with grid with 3 lines of code, but I can´t figgure it out using flex in the parent.
<div class=items-container>
<div class="item1">item 1</div>
<div class="item2">item 2</div>
<div class="item3">item 3</div>
</div>
I left the example in this link:
https://codepen.io/plevindo/pen/porqbXv
Pretty simple, just use flex with flex-wrap on the parent, and the first item set flex-basis to 100%. That will push the siblings to the next line.
.items-container {
display: flex;
flex-wrap: wrap;
}
.item1 {
flex: 1 1 100%;
}
<div class=items-container>
<div class="item1">item 1</div>
<div class="item2">item 2</div>
<div class="item3">item 3</div>
</div>

Is it possible to unwrap a HTML element using CSS? [duplicate]

This question already has answers here:
Is there a way to remove a div but keep its elements?
(2 answers)
Closed 1 year ago.
I have a content management system that generates code like
<div class="container">
<div class="item">Item 1</div>
<div class="item">Item 2</div>
<div class="item">Item 3</div>
</div>
and depending on the query it might also generate
<div class="container">
<div class="section">
<div class="item">Item 1</div>
<div class="item">Item 2</div>
<div class="item">Item 3</div>
</div>
</div>
I want container be a flexbox container, and item be flexbox children in all cases.
Is there a way to unwrap the section element (=make the browser ignore this div layer - so that the item elements will be treated as if they where direct children of container)?
Or is that impossible with pure CSS?
You can do that like this:
.container, .container > .section {
display: flex;
...
}
.container > .item, .container > .section > .item {
...
}
It wouldn’t be a good idea to remove the section element because that is there for a reason. But the css above will take care of both cases.
You can add new rules for case when CMS creates additional tag and then add specificity them to increase chances that correct rule will be applied:
div.container div.section {
display: flex;
}
Read more about specificity here
As far as children elements are concerned, .section is a child element of .container and .item elements are children of .section. There isn't a way to ignore this via CSS.
I'd recommend you copy the styles of .container to .section and just make the necessary adjustments there.
It would help if you shared your current styles.

Centering grid items in an auto-fill container

I have set up a grid with two items. This grid can contain any number of items but two is enough for this example.
Background
In the example there are two gray boxes align to the left. Using an inspector on a wide screen (above 1000px) we can spot a third (or more) "shadow" item that fills up the rest of the space.
Question
How can I center the boxes in the grid? Like the "shadow" item(s) does not exist.
On the .grid element I still want to use a grid because of the automatic media queries I don't need to write. On the wrapper, anything goes.
Also, a fixed width is not an option.
.wrap {
display: flex;
flex-direction: column;
/*justify-content: center;
align-items: center;*/
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
grid-gap: 1rem;
}
.item {
background: #eee;
}
<div class="wrap">
<div class="grid">
<div class="item">
Item 1
</div>
<div class="item">
Item 2
</div>
</div>
</div>
Fiddle
https://jsfiddle.net/1ymkg327/4/
Flexbox
The most efficient solution to your problem is probably flexbox, as flex items are not confined to individual tracks (columns/rows) like grid items.
.grid {
display: flex;
flex-wrap: wrap;
margin-bottom: 1em;
}
.item {
flex: 1 0 100px;
background: #eee;
text-align: center;
border: 1px dashed gray;
box-sizing: border-box;
}
<div class="grid">
<div class="item">Item 1</div>
</div>
<div class="grid">
<div class="item">Item 1</div>
<div class="item">Item 2</div>
</div>
<div class="grid">
<div class="item">Item 1</div>
<div class="item">Item 2</div>
<div class="item">Item 3</div>
</div>
<div class="grid">
<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>
But if you want to stick with Grid Layout, here are some issues to consider and a potential solution.
Grid
1fr
When you say 1fr, like you do in your code, that means "consume all free space". But when there is no free space, there can be no alignment.
Keyword alignment properties (i.e. justify-* and align-*) work by distributing free space. They cannot left-align, right-align, space-between, space-around or center, without free space.
This isn't just Grid behavior. It's standard HTML/CSS: A div is a block-level element by default. This means it occupies 100% width of its parent. So a div cannot be centered (unless you override the default settings).
Structure
Columns and rows in a grid extend across the entire container. So once auto-fill creates, let's say, three columns, all following rows will have three columns.
If the first row has three grid items and the second row has two grid items, there is still a third column going through (and occupying space) on the second row. Therefore, the two items in the second row cannot be centered on the line.
auto-fill
When the repeat() function is set to auto-fill or auto-fit, the container creates as many grid tracks as possible without overflowing the container.
With auto-fill, when there are no grid items to fill all tracks created, those tracks are preserved. Basically, the grid layout remains fixed, with or without items.
You pointed this out in your question. You have two grid items, but other "shadow" items also exist. Just note that these "shadow" items are not grid items. They are just empty grid cells.
Because of the empty grid cells, there is no free space left for centering the grid items.
auto-fit
The auto-fit keyword does the same as auto-fill, except for this: empty tracks are collapsed.
In your case, since you have 1fr set as the max-size in the minmax() function, the extra space is distributed among both grid items.
Again, centering is not possible, but this time because the fr unit is consuming all free space (as explained in the 1fr section above).
justify-content: center
As described above, centering the grid items is not possible because there is no free space available on the line for alignment purposes.
One way around this, which still allows for flexible column sizes, is to use max-content instead of 1fr, along with auto-fit.
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(100px, max-content));
justify-content: center;
grid-gap: 1rem;
}
.item {
background: #eee;
}
<div class="grid">
<div class="item">Item 1</div>
</div>
<hr>
<div class="grid">
<div class="item">Item 1</div>
<div class="item">Item 2</div>
</div>
<hr>
<div class="grid">
<div class="item">Item 1</div>
<div class="item">Item 2</div>
<div class="item">Item 3</div>
</div>
<hr>
<div class="grid">
<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>
More Info
The difference between auto-fill and auto-fit
max-content in the spec
The problem is that using auto-fill you're creating a lot of empty columns, which makes justify-items:center not behave as you'd expect it to.
You need to use auto-fit instead.
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
grid-gap: 1rem;
justify-items:center;
}
https://jsfiddle.net/1ymkg327/36/
That's because of the max value set with minmax is too small.
You need to set the max value to 50%. Because you have grid-gap:1rem this become calc(50% - 1rem).
See this fiddle:
https://jsfiddle.net/1ymkg327/24/
EDIT:
I unerstood your question now, and come up with the solution:
https://jsfiddle.net/1ymkg327/40/

Align cells in rows *and* columns in a flexbox layout

Is there any way to align cells in rows and columns (like in a table) using flexbox ?
To make things clear, what I would like is to align cells in the table below.
Of course I could add some flex: XXX but the problem is I don't want to fix the width of the columns.
I have gotten used to flex fixing everything but I feel kind of stuck... So is there no solution apart from going back to display: table or html <table>s...?
Here is a fiddle if you want to play with it :)
.myCell {
border: solid black 1px;
padding: 10px;
}
.myTable {
display: flex;
flex-direction: column;
}
.myRow {
display: flex;
flex-direction: row;
}
<div class="myTable">
<div class="myRow">
<div class="myCell">ROW 1, CELL 1</div>
<div class="myCell">ROW 1, CELL 2</div>
<div class="myCell">ROW 1, CELL 3</div>
</div>
<div class="myRow">
<div class="myCell">A LONGER CELL</div>
<div class="myCell">ROW 2, CELL 2</div>
<div class="myCell">ROW 2, CELL 3</div>
</div>
</div>
The future replacement for CSS Table is CSS Grid, not Flexbox.
That said, you can make Flexbox behave as a table, kind of, but not replace it fully, and as you seem to look for a column/row layout, use CSS Table (and that is not going back)