Flex Row space between wrapped items - css

What is the most dynamic way of having any amount of rows with any amount of items with a set margin between all the items? Right now the only thing that works for me is to wrap each item in a wrapper set the flex basis to the wrapper and the margin to the child. The issues with this is I loose the ability to have each row the same height of the tallest content in the row.
Case 1: Only margin bottom
https://jsfiddle.net/6oaney4e/6/
This works well because the content keep the height of the tallest item on each row
html
<div class="wrapper">
<div class="item">
text
</div>
<div class="item">
text
<br>
line2
</div>
<div class="item">
text
</div>
<div class="item">
text
</div>
</div>
css
.wrapper{
display: flex;
flex-flow: row wrap;
margin: -10px;
padding: 10px;
background: green;
}
.item{
flex: 0 0 50%;
background: orange;
margin-bottom: 10px;
}
Case 2: All around margin
https://jsfiddle.net/6oaney4e/7/
Here for some reason the rows break I'm guessing that's because the row cant fit the items in with the extra margin on the side.
html same as CASE 1
css
.wrapper{
display: flex;
flex-flow: row wrap;
margin: -10px;
padding: 10px;
background: green;
}
.item{
flex: 0 0 50%;
background: orange;
margin: 10px;
}
Case 3: Wrapping items and adding margin to the inner item
https://jsfiddle.net/6oaney4e/8/
That worked but now the items on each row arent really aware of each other and cant have the same height.
html
<div class="wrapper">
<div class="item-wrap">
<div class="item">
text
</div>
</div>
<div class="item-wrap">
<div class="item">
text
<br>
line2
</div>
</div>
<div class="item-wrap">
<div class="item">
text
</div>
</div>
<div class="item-wrap">
<div class="item">
text
</div>
</div>
</div>
css
.wrapper{
display: flex;
flex-flow: row wrap;
margin: -10px;
padding: 10px;
background: green;
}
.item-wrap{
flex: 0 0 50%;
}
.item{
background: orange;
margin: 10px;
}
Is there a way to keep the HTML as in CASE 1 (without the div.item-wrap), have the items on each row the same height as in CASE 1 and have the spacing work like in CASE 3?

Ideally, you do want to use rows and make the .item-wrap divs flex-parents too.
.wrapper {
display: flex;
flex-flow: row wrap;
margin: -10px;
padding: 10px;
background: green;
}
.item-wrap {
flex: 0 0 50%;
display: flex;
}
.item {
background: orange;
margin: 10px;
flex: 1;
}
<div class="wrapper">
<div class="item-wrap">
<div class="item">
text
</div>
</div>
<div class="item-wrap">
<div class="item">
text
<br> line2
</div>
</div>
<div class="item-wrap">
<div class="item">
text
<br> line2
<br> line3
</div>
</div>
<div class="item-wrap">
<div class="item">
text
</div>
</div>
</div>
However if you must retain the existing structure, you'll need to use calc to adjust the flex-basis. Something like this:
.wrapper {
display: flex;
flex-flow: row wrap;
background: green;
justify-content: space-between;
}
.item {
flex-grow:0;
flex-shrink:0;
flex-basis:calc(50% - 10px); /* separate properties for IE11 upport */
background: orange;
margin: 5px;
}
<div class="wrapper">
<div class="item">
text
</div>
<div class="item">
text
<br> line2
</div>
<div class="item">
text
<br> line2
<br> line3
</div>
<div class="item">
text
</div>
</div>

Related

How do you align text vertically at a proportion in a flexbox?

For example I have the following html and css. Container has a height of 88px, and each div in container contains a span and should have half the height of container. I wish to align the spans at a proportion, like at 1/3 height in their divs. Also, the divs might contain things other than a span which might occupy full 44px height, and in that case I wouldn't want it to clip out of it's div. How do I achieve this?
.container{
height: 88px;
display:flex;
flex-direction: column;
}
.line{
flex: 1;
border: solid 1px;
}
<div class="container">
<div class="line">
<span>This is line 1</span>
</div>
<div class="line">
<span>This is line 2</span>
</div>
</div>
I don't know if I fully understood the question, but you can can use the flex: 1 0 33%; on the element, this way it will occupy 33% of the parent div, but will grow if it has space.
And for the vertical-alignment you can use another flex with align-items: center;
You can read more about flex here, and about flex sizing and positioning here
.container {
display: flex;
flex-direction: column;
height: 88px;
margin-bottom: 10px;
}
.line {
display: flex;
align-items: center;
flex: 1 0 33%;
border: 1px solid #000;
}
<div class="container">
<div class="line">
This is line 1
</div>
<div class="line">
This is line 2
</div>
<div class="line">
This is line 2
</div>
</div>
<div class="container">
<div class="line">
This is line 1
</div>
<div class="line">
This is line 2
</div>
</div>

How to make a flex element grow and shrink between two predefined width?

I am trying to make two flex elements shrink and grow, while one of their children div elements have predefined min and max widths.
If I have too much space available, I'd like my two elements to be displayed next to each other without the elements or the inner divs growing more than the max width.
If I don't have enough space available, I'd like my two inner divs to keep their min width and the flex elements to be wrapped.
My best attempt is the following:
.bigcontainer {
display: flex;
flex-wrap: wrap;
}
.container {
display: flex;
flex-wrap: nowrap;
flex: 1 1 auto;
}
.a {
flex: 0 0 auto;
}
.b {
flex: 0 1 400px;
}
.c {
flex: 1 0 auto;
}
.sizedContent {
background-color: lightcoral;
height: 15px;
min-width: 200px;
}
<div class="bigcontainer">
<div class="container">
<div class="a">
a
</div>
<div class="b">
<div class="sizedContent">
</div>
</div>
<div class="c">
c
</div>
</div>
<div class="container">
<div class="a">
a
</div>
<div class="b">
<div class="sizedContent">
</div>
</div>
<div class="c">
c
</div>
</div>
</div>
Codepen pen.
The inner divs are growing and shrinking as I want them to. However there is an unwanted white space between the two because the flex element is growing as well.
Has someone a better idea how to implement this?
To remove the space between flex elements, switch from display: flex to display: inline-flex.
revised codepen
.bigcontainer {
display: inline-flex; /* adjustment */
flex-wrap: wrap;
}
.container {
display: flex;
flex-wrap: nowrap;
flex: 1 1 auto;
}
.a {
flex: 0 0 auto;
}
.b {
flex: 0 1 400px;
}
.c {
flex: 1 0 auto;
}
.sizedContent {
background-color: lightcoral;
height: 15px;
min-width: 200px;
}
<div class="bigcontainer">
<div class="container">
<div class="a">a</div>
<div class="b">
<div class="sizedContent"></div>
</div>
<div class="c">c</div>
</div>
<div class="container">
<div class="a">a</div>
<div class="b">
<div class="sizedContent"></div>
</div>
<div class="c">c</div>
</div>
</div>

Flex box - arrange items in column with multiple elements on each row if space allows

I want to arrange some items of variable width in a column, where the column has a fixed width. But I want elements to stack up next to each other if the total width of a group of elements doesn't exceed the column width. In the snippet, I want to add CSS to the first container so that that the 2nd and 3rd divs will be next to each other, as they are in the second container. I don't know the element widths in advance so I can't just do this manually by putting divs around the elements that should be adjacent. I want to also accomplish with just flexbox, not CSS grids if that's also a solution.
.container {
width: 500px;
border: 1px solid red;
}
.flexcol {
display: flex;
flex-direction: column;
align-items: center;
}
.inlineblock > div {
display: inline-block;
}
.item {
border: 1px solid black;
font-size: 24pt;
text-align: center;
}
.item1, .item4 {
width: 400px;
}
.item2, .item3 {
width: 200px;
}
<div class="container flexcol">
<div class="item item1">
Item 1
</div>
<div class="item item2">
Item 2
</div>
<div class="item item3">
Item 3
</div>
<div class="item item4">
Item 4
</div>
</div>
<div class="container flexcol">
<div class="item item1">
Item 1
</div>
<div class="inlineblock">
<div class="item item2">
Item 2
</div>
<div class="item item3">
Item 3
</div>
</div>
<div class="item item4">
Item 4
</div>
</div>
Fiddle here of same code: https://jsfiddle.net/6ycer7b0/1/
You can do this with a row direction and enable the wrap to simulate a column behavior as the elements will stack above each other:
.container {
width: 500px;
border: 1px solid red;
}
.flexcol {
display: flex;
flex-direction: row;
flex-wrap:wrap;
justify-content: center;
}
.item {
border: 1px solid black;
font-size: 24pt;
text-align: center;
}
.item1, .item4 {
width: 400px;
}
.item2, .item3 {
width: 200px;
}
<div class="container flexcol">
<div class="item item1">
Item 1
</div>
<div class="item item2">
Item 2
</div>
<div class="item item3">
Item 3
</div>
<div class="item item4">
Item 4
</div>
</div>

Flexbox: row with inline-flex + fixed item width (fixing flex-basis bug): not working inside column layout

I want to get a table in CSS with a sticky header (only body scrolls) on Y, and whole table scrolls on X.
According to Michael_B comment on my previous question here there is a flexbox bug and I have to use inline-flex on row + width on cells to make sure my row grows correctly.
This leads me to this result:
html, body {
width: 100%;
min-height: 100vh;
margin: 0;
padding: 0;
}
body {
display: flex;
align-items: center;
justify-content: center;
}
.table {
border: solid black;
width: 60vw;
height: 80vh;
overflow-x: auto;
display: flex;
flex-direction: column;
}
.header {
border: solid cyan;
flex: 0;
}
.body {
flex: 1;
overflow-y: auto;
border: solid yellow;
display: inline-block;
}
.row {
border: solid red;
display: inline-flex;
flex-direction: row;
align-items: center;
}
.cell {
border: solid green;
width: 400px;
height: 50px;
}
<div class="table">
<div class="header">
<div class="row">
<div class="cell">
cell 1
</div>
<div class="cell">
cell 2
</div>
<div class="cell">
cell 3
</div>
</div>
</div>
<div class="body">
<div class="row">
<div class="cell">
cell 1
</div>
<div class="cell">
cell 2
</div>
<div class="cell">
cell 3
</div>
</div>
<div class="row">
<div class="cell">
cell 1
</div>
<div class="cell">
cell 2
</div>
<div class="cell">
cell 3
</div>
</div>
<div class="row">
<div class="cell">
cell 1
</div>
<div class="cell">
cell 2
</div>
<div class="cell">
cell 3
</div>
</div>
</div>
</div>
JsFiddle
As you can see it's not exactly what I want. It seems my rows do not grow according to their content size even with inline-flex, and this happens only when using a flex column layout on the table.
html, body {
width: 100%;
min-height: 100vh;
margin: 0;
padding: 0;
}
body {
display: flex;
align-items: center;
justify-content: center;
}
.table {
border: solid black;
width: 60vw;
height: 80vh;
overflow-x: auto;
}
.header {
border: solid cyan;
flex: 0;
display: inline-block;
height: 50px;
}
.body {
flex: 1;
overflow-y: auto;
border: solid yellow;
display: inline-block;
height: calc(100% - 50px - 16px);
}
.row {
border: solid red;
display: inline-flex;
flex-direction: row;
align-items: center;
}
.cell {
border: solid green;
width: 400px;
height: 50px;
}
By removing flex column, using inline-block and calc computations, I almost get the behavior I want, except I'd like the scrollY scrollbar to always stay visible
<div class="table">
<div class="header">
<div class="row">
<div class="cell">
cell 1
</div>
<div class="cell">
cell 2
</div>
<div class="cell">
cell 3
</div>
</div>
</div>
<div class="body">
<div class="row">
<div class="cell">
cell 1
</div>
<div class="cell">
cell 2
</div>
<div class="cell">
cell 3
</div>
</div>
<div class="row">
<div class="cell">
cell 1
</div>
<div class="cell">
cell 2
</div>
<div class="cell">
cell 3
</div>
</div>
<div class="row">
<div class="cell">
cell 1
</div>
<div class="cell">
cell 2
</div>
<div class="cell">
cell 3
</div>
</div>
</div>
</div>
JsFiddle
Anyone knows how I could achieve the table layout I want? I'm open for no flexbox solution but I don't want a JS based solution for now.

flexbox height adjust to content

I use a "full design" flexbox.
I have a weird issue : I have a container that takes all the remaining space and I want in this container that the child, which is also flexbox, to have their height adjust to their content.
Here is the issue:
body, html {
width:100%;
height:100%;
display:flex;
}
.container {
display:flex;
flex:1;
flex-wrap:wrap;
}
.icon {
width:10vh;
margin:10px;
display:flex;
flex-direction:column;
}
.img {
width:10vh;
height:10vh;
display:flex;
align-items:center;
justify-content:center;
background-color:red;
}
.text {
text-align:center;
}
<div class="container">
<div class="icon">
<div class="img">
</div>
<div class="text">
action 1
</div>
</div>
<div class="icon">
<div class="img">
</div>
<div class="text">
Action 2
</div>
</div>
<div class="icon">
<div class="img">
</div>
<div class="text">
Action 3
</div>
</div>
<div class="icon">
<div class="img">
</div>
<div class="text">
Action 4
</div>
</div>
<div class="icon">
<div class="img">
</div>
<div class="text">
Action 5
</div>
</div>
</div>
As you can see, the icon takes the full height of the container : in fact, I don't want to specify a height because I don't know the text length and really want that, if the content is huge, the icon takes the height of its content ( don't want to cut the text). Moreover, if the page is resized, I really want the icon to be aligned (like on smartphone).
Also, I don't understand why the icon takes the height of its parent and not its content because I didn't specify "flex:1" on it. I assume that the default behaviour it's to fit the content size, but this seems not to be working.
image of the issue
.icon's are flex-column which makes .img's stretch by default unless .icon's have align-items. The reason why I didn't apply align-items to .icon's is because other nested flex-containers/flex-items started collapsing. Instead of adjusting down through the hierarchy, I went up and adjusted .container instead.
The relevant CSS:
.container {
display: flex;
flex: 1; /* If you remove this .container will shrink to wrap around .icon's */
flex-wrap: wrap;
justify-content: center; /* This centers .icon's along a horizontal axis. */
align-items: baseline; /* This aligns .icon's along a common baseline vertically. */
outline: 3px dashed blue; /* To show the size of .container */
}
.icon {
width: 10vh;
margin: 10px;
display: flex;
flex-direction: column;
outline: 1px dashed red; /* To show the size of .icon */
}
body,
html {
width: 100%;
height: 100%;
display: flex;
}
.container {
display: flex;
flex: 1;
flex-wrap: wrap;
justify-content: space-between;
align-items: baseline;
align-content: flex-start;
outline: 3px dashed blue;
}
.icon {
width: 10vh;
margin: 10px;
display: flex;
flex-direction: column;
outline: 1px dashed red;
}
.img {
width: 10vh;
height: 10vh;
display: flex;
align-items: center;
justify-content: center;
background-color: red;
}
.text {
text-align: center;
}
<div class="container">
<div class="icon">
<div class="img">
</div>
<div class="text">
Action 1
</div>
</div>
<div class="icon">
<div class="img">
</div>
<div class="text">
Action 2
</div>
</div>
<div class="icon">
<div class="img">
</div>
<div class="text">
Action 3
</div>
</div>
<div class="icon">
<div class="img">
</div>
<div class="text">
Action 4
</div>
</div>
<div class="icon">
<div class="img">
</div>
<div class="text">
Action 5
</div>
</div>
</div>

Resources