css: flexbox last row has double the height - html

I played a bit with flexboxes and tried to imitate a LaTeX-like table with top/mid/bottomrule. I like that the table is scaling nicely and shift to a list-like display on small screens.
However, I noticed that, if I use a whitespace in a cell's text content, the cell's height might double or even triple without any aparent reason.
Is there a flexbox-property that I overlooked and can help me fix this behavior? Why is this additional height even generated?
Screenshot:
Snippet:
div.table {
display: flex;
flex-flow: column wrap;
width: 70%;
margin: 15px auto;
border-bottom: 2px solid black;
}
div.row {
display: flex;
justify-content: space-between;
flex-flow: row wrap;
}
div.head {
flex: 1;
text-align: center;
align-items: flex-start;
font-weight: bold;
border-width: 2px 0 1px;
border-style: solid;
}
div.item {
flex: 1;
text-align: center;
align-items: flex-start;
}
<div class="table">
<div class="row">
<div class="head">Col 1</div>
<div class="head">Col 2</div>
</div>
<div class="row">
<div class="item">Cell 1</div>
<div class="item">Cell2</div>
</div>
<div class="row">
<div class="item">Cell 3</div>
<div class="item">Cell 4</div>
</div>
</div>

The problem is that, initially, .row is sized taking only the contents of .items into account. Then .items flex, and become equally wide due to flex: 1. But the contents weren't equally wide, so the longest will wrap to a second line.
It's better shown in this example:
.row {
display: inline-flex;
margin: 2px;
}
.item {
border: 1px solid;
}
.flex {
flex: 1;
}
<div class="row">
<div class="item">Cell 11111</div>
<div class="item">Cell 2</div>
(before flex)
</div>
<br />
<div class="row">
<div class="item flex">Cell 11111</div>
<div class="item flex">Cell 2</div>
(after flex)
</div>
In your example you have Cell 1 (with space) and Cell2 (without), which produces the difference.
Eventually the .row also flexes and thus a new line is no longer needed, but it seems browsers don't detect that. It's hard to say, but I think this is right. That's because
The hypothetical main size (height) of the rows is calculated, and
If a cross size is needed to determine the main size (e.g. when the
flex item’s main size is in its block axis) and the flex item’s cross
size is auto and not definite, in this calculation use fit-content as
the flex item’s cross size.
Rows flex. This determines their used height.
Cross sizes (widths) are determined. The rows are stretched to fill the table horizontally. But its too late, heights have already been calculated.
Since your column layout won't wrap because .table has an auto height, I would just use the default flex-wrap: nowrap. It fixes the problem because now the flex container will be single-line, and thus the widths of the rows will be definite:
If a single-line flex container has a definite cross size, the outer
cross size of any stretched flex items is the flex container’s inner
cross size (clamped to the flex item’s min and max cross size) and is
considered definite.
div.table {
flex-flow: column;
}
div.table {
display: flex;
flex-flow: column;
width: 70%;
margin: 15px auto;
border-bottom: 2px solid black;
}
div.row {
display: flex;
justify-content: space-between;
flex-flow: row wrap;
}
div.head {
flex: 1;
text-align: center;
align-items: flex-start;
font-weight: bold;
border-width: 2px 0 1px;
border-style: solid;
}
div.item {
flex: 1;
text-align: center;
align-items: flex-start;
}
<div class="table">
<div class="row">
<div class="head">Col 1</div>
<div class="head">Col 2</div>
</div>
<div class="row">
<div class="item">Cell 1</div>
<div class="item">Cell2</div>
</div>
<div class="row">
<div class="item">Cell 3</div>
<div class="item">Cell 4</div>
</div>
</div>
You can also try explicitly providing an explicit width:
div.row {
width: 100%;
}
Or even preventing text wrapping with whitespace: nowrap.

Just change div.item from flex: 1; to only flex-grow:1;.
Here's the working snippet.
div.table {
display: flex;
width: 70%;
margin: 15px auto;
border-bottom: 2px solid black;
}
div.row {
display: flex;
flex-flow: row wrap;
justify-content: space-between;
}
div.head {
flex: 1;
text-align: center;
align-items: flex-start;
font-weight: bold;
border-width: 2px 0 1px;
border-style: solid;
}
div.item {
flex-grow: 1;
text-align: center;
align-items: flex-start;
}
<div class="table">
<div class="row">
<div class="head">Col 1</div>
<div class="head">Col 2</div>
</div>
<div class="row">
<div class="item">Cell 1</div>
<div class="item">Cell2</div>
</div>
<div class="row">
<div class="item">Cell 3</div>
<div class="item">Cell 4</div>
</div>
</div>

Related

Flex box column showing up as a row (side by side) instead of the next item going into next line

Here is my code, the HTML is probably not of much use
<div class="col-1" v-for="m in messages" :key="m.id">
<div class="message-box">
{{m.id}}
</div>
</div>
here is the CSS
.col-1{
display: flex;
flex-direction: column;
flex-basis: 100%;
flex-wrap: wrap;
flex: 1;
width: 20px;
height: 94vh;
background-color: #747D88;
justify-content:start;
align-items: center;
}
Try to use flex-driection: row and get rid of width prop. You can use min or max -width and using height make sure that you have enough space to wrap items.
check jsfiddle
Just use display: flex and flex-direction: column
.col-1 {
display: flex;
flex-direction: column;
width: 100px;
height: 94vh;
background-color: #747D88;
}
.message-box {
margin: 3px;
background-color: green;
}
<div class="col-1" v-for="m in messages" :key="m.id">
<div class="message-box">
<div>Hello 1</div>
</div>
<div class="message-box">
<div>Hello 2</div>
</div>
<div class="message-box">
<div>Hello 3</div>
</div>
</div>

Changing the size of individual element in flexbox

How can I stretch the items inside a div to fill the area, and is it possible to have the items in different sizes without having to modify individually using :nth-child(x). For instance: first, third and fifth item to be twice as big as second and fourth item?
.my_class_a {
display: flex;
align-items: center;
flex-wrap: wrap;
}
<div class="my_class_a">
<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>
I do apologize because I don't know how to format in fiddle way.
How can I stretch the items inside a div to fill the area...
Use the flex-grow property.
and is it possible to have the items in different sizes without having to modify individually using :nth-child(x).
How is the browser supposed to know what you want if you don't define the behavior?
For instance: first, third and fifth item to be twice as big as second and fourth item?
In this case, you can use the even and odd functions of the nth-child() pseudo class.
.my_class_a {
display: flex;
align-items: center;
flex-wrap: wrap;
}
.item:nth-child(odd) {
flex-grow: 2;
background-color: lightgreen; /* for demo only */
}
.item:nth-child(even) {
flex-grow: 1;
background-color: orange; /* for demo only */
}
/* for aligning item content */
.item {
display: flex;
align-items: center;
justify-content: center;
}
<div class="my_class_a">
<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>
In general you can use flex-grow: 1; to allow flex items to become larger. (Note that i defined a width for the container, otherwise they won't grow)
Concerning your wish about the 2nd, 4th etc. item: You need to define * somewhere* which items should grow and which not, so you you need at least some kind of selector for them.
.my_class_a {
display: flex;
flex-wrap: wrap;
width: 100%;
align-items: center;
}
.item {
border: 1px solid #333;
flex-grow: 1;
padding: 12px;
text-align: center;
}
<div class="my_class_a">
<div class="item">a</div>
<div class="item">b</div>
<div class="item">c<br>c</div>
<div class="item">d</div>
<div class="item">e</div>
</div>
P.S.: To create a snippet (the "fiddle-line" code example, just click the 7th symbol in the toolbar of the answer window)
You can use the flex style declaration - it's a shorthand for:
flex-grow | flex-shrink | flex-basis
where flex-basis is the initial width of the flexbox child and flex-grow and flex-shrink determine how quickly the flexbox child will grow or shrink relative to its siblings.
For instance:
an element with flex: 2 2 100px starts with a width of 100px and will grow or shrink twice as fast as flex: 1 1 50px which starts with a width of 50px.
Working Example:
.my_class_a {
display: flex;
width: 100%;
align-items: center;
}
.item {
color: rgb(255, 255, 255);
text-align: center;
font-weight: bold;
}
.item-a,
.item-c,
.item-e {
flex: 2 2 100px;
background-color: rgb(255, 0, 0);
}
.item-b,
.item-d {
flex: 1 1 50px;
background-color: rgb(0, 0, 0);
}
<div class="my_class_a">
<div class="item item-a">a</div>
<div class="item item-b">b</div>
<div class="item item-c">c</div>
<div class="item item-d">d</div>
<div class="item item-e">e</div>
</div>

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>

How to use `flex: grow` on floating content?

I have a header with 2 rows of 2 Foundation columns of content, as below:
<div class="wrapper">
<div class="header row">
<div class="large-6 columns">
HEADER
</div>
<div class="large-6 columns">
menu
</div>
</div>
<div class="row">
<div class="large-5 none show-for-medium columns info">
Some information to the left
</div>
<div class="large-7 columns">
<div class="image-container">
<div class="image">
image to the right
</div>
</div>
</div>
</div>
</div>
The .header height is dynamic and not set. I want the .image element to take up 100% of the remaining vertical space.
eg:
To that affect I have tried using flex and flex-grow, eg:
.wrapper {
display: flex;
flex-direction: column;
min-height: 100vh;
width: 100%;
}
.image-container {
flex-grow: 1;
}
but had no luck, see fiddle: https://jsfiddle.net/9kkb2bxu/46/
Would anyone know how I could negate the dynamic height of the header from the 100vh of the image container?
.wrapper {
display: flex;
flex-direction: column;
min-height: 100vh;
width: 100%;
border: 1px solid black;
background-color: #ccc;
}
.row {
width: 100%;
}
.header {
background-color: green;
}
.info {
background-color: yellow;
border: 1px solid #ccc;
}
.image-container {
border: 1px solid black;
display: flex;
}
.image {
background-color: red;
flex-grow: 1;
width: 100%;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/foundation/6.3.1/css/foundation.min.css" rel="stylesheet"/>
<div class="wrapper">
<div class="header row">
<div class="large-6 columns">
<h1>
HEADER
</h1>
</div>
<div class="large-6 columns">
<h1>
menu
</h1>
</div>
</div>
<div class="row">
<div class="large-5 none show-for-medium columns info">
Some information to the left
</div>
<div class="large-7 columns">
<div class="image-container">
<div class="image">
image to the right
</div>
</div>
</div>
</div>
</div>
Set the second row to take up the rest of the remaining height with flex: 1 and make sure you nest that flex with display: flex:
.row.target-row {
flex: 1;
display: flex;
}
Set the .image-container to 100% height of its column parent.
.image-container {
height: 100%;
}
By default both columns will expand. Stop the left column from expanding with:
.large-5 {
align-self: flex-start;
}
(flex-start reference: https://stackoverflow.com/a/40156422/2930477)
Complete Example
.wrapper {
display: flex;
flex-direction: column;
min-height: 100vh;
width: 100%;
border: 1px solid black;
background-color: #ccc;
}
.row {
width: 100%;
}
.header {
background-color: green;
}
.info {
background-color: yellow;
border: 1px solid #ccc;
}
.image-container {
height: 100%;
background-color: red;
}
.large-5 {
align-self: flex-start;
}
.row.target-row {
flex: 1;
display: flex;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/foundation/6.3.1/css/foundation.min.css" rel="stylesheet" />
<div class="wrapper">
<div class="header row">
<div class="large-6 columns">
<h1>
HEADER
</h1>
</div>
<div class="large-6 columns">
<h1>
menu
</h1>
</div>
</div>
<div class="row target-row">
<div class="large-5 none show-for-medium columns info">
Some information to the left
</div>
<div class="large-7 columns">
<div class="image-container">
<div class="image">
image to the right
</div>
</div>
</div>
</div>
</div>
flex-grow only applies to flex children.
.image-container isn't a direct child of a display: flex element, so that property has no effect.
Plus, it affects the flex axis, which is not what you want.
Instead, you need to put those two elements in their own flex row, and use align-items (on the parent) and align-self (on either child) so that the first one aligns (on the cross axis) to flex-start (stick to top) and the second one to stretch.
You'll also want that flex row (parent) to have flex-grow: 1 so that it stretches along the vertical flex axis of its parent (.wrapper) to fill the rest of the page (otherwise, the grandchild will have nothing to stretch to).
For more information, read a good flex tutorial.
div.wrapper > div:not(.header).row {
flex: 1; /* 1 */
display: flex; /* 1 */
}
div.large-7.columns {
display: flex; /* 2 */
}
div.image-container { /* 3 */
flex: 1;
}
div.large-5.show-for-medium { /* 4 */
align-self: flex-start;
}
jsFiddle
Notes:
flex container and items consume all remaining height of respective parents
give children full height (via align-items: stretch initial setting)
flex item consumes all available width
yellow box does not need to expand to full height; now set to content height

How to shrink flex items height to fit container heights

I am trying to display a layout below in flex .
I have divs of equal width and height. I want to achieve the layout out below. By placing one item on the left and the remaining four fit on the right container and maintaining the same container height in the process . Thats the one on the left increase to fill the left height and width and the other right size of the container is shared among the four items.
.trades {
display: flex;
flex: 1;
}
.trade-panel {
flex: 1;
}
.layout-5-2 {
-ms-flex-direction: row;
flex-direction: row;
justify-content: space-between;
display: flex;
}
.layout-container-5-2-1 {
-ms-flex-direction: column;
flex-direction: column;
height: 100%;
justify-content: space-between;
flex: 0 0 48%;
display: flex;
}
.layout-container-5-2-2 {
flex: 0 0 48%;
display: flex;
flex-direction: column;
}
<div class="trades">
<div class="layout-5-2">
<div class="layout-container-5-2-1">
<div class="trade-panel">item 1</div>
<div class=" trade-panel">item 2</div>
<div class="trade-panel">item 3</div>
<div class=" trade-panel">item 4</div>
</div>
<div class="layout-container-5-2-1">
<div class="trade-panel">vertical item.</div>
</div>
</div>
</div>
My layout displays close to what i was expecting.with four to in the container to the right and one item to the left. However, The trades container scroll vertically to accommodate the four trades height. The trades does not shrink to fit into the right container thats .layout-container 5-2-2. Please how do i shrink the four to fix in the container heights ? Any help would be appreciated.
Try this
body,
html {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container {
display: flex;
min-height: 100vh;
background: #2A3052;
}
.left {
flex: 1;
background: #9497A8;
margin: 10px;
}
.right {
flex: 1;
display: flex;
flex-direction: column;
}
.box {
flex: 1;
background: #9497A8;
margin: 10px;
}
<div class="container">
<div class="left"></div>
<div class="right">
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
</div>
</div>