Expand divs in column layout to match original height of parent - css

As the title specifies: I have a number of divs in a column layout, and I would like them to expand to match the original height of the parent.
The parent doesn't have a fixed height, as it is part of a flex-based page layout.
Is this possible? In the attached example, I would like both .child divs to be equal in height, and the same height as the original height of the parent.
I can believe that it is impossible based on the way that CSS works.
body {
margin: 0;
}
.container {
display: flex;
flex-direction: column;
min-height: 100vh;
}
.parent {
flex: 1;
}
.child {
border: 1px solid black;
}
<div class="container">
<div class="header">Header</div>
<div class="parent">
<div class="child">Child 1</div>
<div class="child">Child 2</div>
</div>
<div class="footer">Footer</div>
</div>

You may imbricate flex boxes.
body {
margin: 0;
}
.container ,.parent{
display: flex;
flex-direction: column;
min-height: 100vh;
}
.parent, .child {
flex: 1;
min-height:auto;
}
.child {
border: 1px solid black;
}
<div class="container">
<div class="header">Header</div>
<div class="parent">
<div class="child">Child 1</div>
<div class="child">Child 2</div>
</div>
<div class="footer">Footer</div>
</div>
For the other part of the question : the same height as the original height of the parent. sibblings or parent of .container looks like missing to visualize how height is applied or comes from.
Could be something alike:
body {
margin: 0;
}
.container,
.parent {
display: flex;
flex-direction: column;
min-height: 100vh;
}
.parent {
flex: 1;
min-height: auto;
overflow: auto;
}
.child {
flex: 1;
min-height: 100%;
border: 1px solid black;
}
* {
box-sizing: border-box;
}
<div class="container">
<div class="header">Header</div>
<div class="parent">
<div class="child">Child 1</div>
<div class="child">Child 2</div>
</div>
<div class="footer">Footer</div>
</div>
edit , from comment
For chrome, A bit of js can used to set a usable min-height value for that browser (and others).
let MyParent = document.querySelector('.parent');
let MyParentH = MyParent.offsetHeight;
MyParent.style.setProperty("--MyHeight", MyParentH +"px");
body {
margin: 0;
}
.container,
.parent {
display: flex;
flex-direction: column;
min-height: 100vh;
}
.parent {
flex: 1;
min-height: auto;
overflow: auto;
}
.child {
flex: 1;
min-height: 100%;/* where var css is not supported */
min-height:var(--MyHeight, 100%);
border: 1px solid black;
}
* {
box-sizing: border-box;
}
<div class="container">
<div class="header">Header</div>
<div class="parent">
<div class="child">Child 1</div>
<div class="child">Child 2</div>
</div>
<div class="footer">Footer</div>
</div>

give 100% of the parents width to its children.
.parent {
display: 'flex';
flex-direction: column;
height: 100%;
}
.child {
border: 1px solid black;
height: 100%;
}

Do you want something like that?
body {
margin: 0;
}
.container {
display: flex;
flex-direction: column;
min-height: 100vh;
}
.parent {
flex: 1;
display: flex;
}
.child {
border: 1px solid black;
}
<div class="container">
<div class="header">Header</div>
<div class="parent">
<div class="child">Child 1</div>
<div class="child">Child 2</div>
</div>
<div class="footer">Footer</div>
</div>
PS: Update my answer with comment advice
body {
margin: 0;
}
.container {
display: flex;
flex-direction: column;
min-height: 100vh;
}
.parent {
flex: 1;
display: flex;
flex-direction: column;
}
.child {
border: 1px solid black;
flex-grow: 1;
}
<div class="container">
<div class="header">Header</div>
<div class="parent">
<div class="child">Child 1</div>
<div class="child">Child 2</div>
</div>
<div class="footer">Footer</div>
</div>

Related

How to move a flex container to the right?

I have a flex container that contains a varying number of other flex containers. I'm trying to get the outermost container to be justified to the right and only take up 60% of the available width. Then I want to have another flex container take up that space on the left. #Feed is the outermost container and the .tweets are its children. #friends is the independent flex container.
#feed {
display: flex;
flex-direction: column;
box-sizing: border-box;
width: 60%;
}
.tweet {
display: flex;
border: 2px solid red;
border-radius: 25px;
flex: 1;
flex-wrap: wrap;
}
#friends {
display: flex;
}
Here is an example of two flex items taking up 40% and 60% space.
#wrapper {
display: flex;
}
.column-40 {
width: 40%;
background: lightgray;
}
.column-60 {
width: 60%;
background: grey;
}
.tweet {
border: 1px solid blue;
}
<div id="wrapper">
<div class="column-40">
<div class="tweet">tweet</div>
<div class="tweet">tweet</div>
<div class="tweet">tweet</div>
</div>
<div class="column-60">
<div class="tweet">tweet</div>
<div class="tweet">tweet</div>
<div class="tweet">tweet</div>
</div>
</div>
When you just want the 60% wrapper to be aligned right you can remove the first column and justify the content to the end:
#wrapper {
display: flex;
justify-content: flex-end;
}
.column-60 {
width: 60%;
}
.tweet {
border: 1px solid blue;
}
<div id="wrapper">
<div class="column-60">
<div class="tweet">tweet</div>
<div class="tweet">tweet</div>
<div class="tweet">tweet</div>
</div>
</div>

How do I mimic floats with flexbox?

I am trying to use flexbox like floats. I would like 1 child to form a column on the right and the remaining children to form another column on the left. I can't add in additional HTML -- I can only work with CSS.
I've figured out how to do this, but I just need both columns to align at the top. My current code has the left column slightly below the right column.
https://jsfiddle.net/o2fbtuLc/
.parent {
display: flex;
flex-wrap: wrap;
flex-direction: column;
}
.child {
max-width: 48%;
}
.right {
margin-left: auto;
}
<div class="parent">
<div class="child right">Right</div>
<div class="child">Left</div>
<div class="child">Left</div>
<div class="child">Left</div>
</div>
You can use order. Also I removed flex-direction: column and added max-width: 100% for elements after second element.
.parent {
display: flex;
flex-wrap: wrap;
}
.child {
width: 100%;
max-width: 48%;
}
.child:nth-child(2) {
order: 1;
}
.child:nth-child(3) {
order: 3;
}
.child:nth-child(4) {
order: 4;
}
.right {
order: 2;
}
.child:nth-child(n + 3) {
max-width: 100%;
}
<div class="parent">
<div class="child right">Right</div>
<div class="child">Left</div>
<div class="child">Left</div>
<div class="child">Left</div>
</div>
If .right is taller, we can consider using grid-area.
.parent {
display: grid;
grid-template-areas: "left1 right"
"left2 right"
"left3 right";
}
.child {
width: 100%;
background: blue;
height: 30px;
}
.child:nth-child(2) {
grid-area: left1;
}
.child:nth-child(3) {
grid-area: left2;
}
.child:nth-child(4) {
grid-area: left3;
}
.right {
background: red;
height: 80px;
grid-area: right;
}
<div class="parent">
<div class="child right">Right</div>
<div class="child">Left</div>
<div class="child">Left</div>
<div class="child">Left</div>
</div>
CSS-Grid can do that:
.parent {
display: grid;
grid-template-columns: auto auto;
grid-auto-flow: column;
}
.child {
max-width: 48%;
grid-column: 1;
border: 1px solid green;
}
.right {
grid-column: 2;
}
<div class="parent">
<div class="child right">Right</div>
<div class="child">Left</div>
<div class="child">Left</div>
<div class="child">Left</div>
<div class="child right">Right</div>
</div>
If you want to avoid grid (IE 11 involved maybe ?) , the old way via the table-display, can do too :
.parent {
display: table;
width: 100%;
direction: rtl;/* alike a flow column reverse here */
text-align: left;
border: solid;
}
.child {
direction: ltr;/* ! reset flow direction ;)*/
border: solid;
}
.right {/* i will also expand if first col is longer than myself */
display: table-cell;
width: 50%;/* set column width here ! left over will be for the other one(s). */
}
/* margins ? */
.bis {border-spacing:2px;}
.bis .child {margin-right:2px;}
.bis .right + .child ~ .child {margin-top:2px;}
.bis .right{text-align:center;vertical-align:middle;
<div class="parent">
<div class="child right">Right</div>
<div class="child">Left</div>
<div class="child">Left</div>
<div class="child">Left</div>
</div>
<hr>
<div class="parent bis">
<div class="child right">possible gaps / VH-align</div>
<div class="child">Left</div>
<div class="child">two<br>lines</div>
<div class="child">Left</div>
</div>
just use flexbox as it was intended!
.parent {
display: flex;
justify-content:space-between;
}
<div class="parent">
<div>
<div class="child">Left</div>
<div class="child">Left</div>
<div class="child">Left</div></div>
<div class="child right">Right</div>
</div>

CSS flex-wrap how to make the height do not stretch [duplicate]

This question already has answers here:
CSS-only masonry layout
(4 answers)
Closed 3 years ago.
There are big gaps between box3, box1 and box4, box6 How to get rid of the gap? so each box could have the dynamic height?
.wrap {
display: flex;
align-items: baseline;
align-content:flex-start;
justify-content: space-between;
flex-wrap: wrap;
background-color: lightblue;
}
.box {
display: flex;
background-color: tomato;
box-sizing: border-box;
border: 1px solid #C4C4C4;
height: 100px;
width: 45%;
margin-top: 15px;
}
.box1, .box4 {
height: 20px;
}
<div class="wrap">
<div class="box box1">box1</div>
<div class="box box2">box2</div>
<div class="box box3">box3</div>
<div class="box box4">box4</div>
<div class="box box5">box5</div>
<div class="box box6">box6</div>
</div>
Here is the desired layout. Thanks
The default direction of flex is row, and when you use flex-wrap: wrap push overflowed element downed to another row, and the row height will default always equal to the highest element of that row, that why you seeing the element having that gap.
This can be done if you change the flex direction to column and give the wrap element a fixed height so it push overflowed element to it right, from top to bottom.
.wrap {
/*Added these*/
height: 300px;
flex-direction: column;
/*-----------*/
display: flex;
align-items: baseline;
align-content: space-around;
flex-wrap: wrap;
background-color: lightblue;
}
.box {
display: flex;
background-color: tomato;
box-sizing: border-box;
border: 1px solid #C4C4C4;
height: 100px;
width: 45%;
margin-top: 15px;
}
.box1, .box5 {
height: 20px;
}
<div class="wrap">
<div class="box box1">box1</div>
<div class="box box2">box2</div>
<div class="box box3">box3</div>
<div class="box box4">box4</div>
<div class="box box5">box5</div>
<div class="box box6">box6</div>
</div>
Since FlexBox is going to attempt to line the boxes up in rows, you have to create two separate FlexBoxes with flex-flow: column set. You can achieve this affect with about the same amount of CSS though:
.outer{
display: flex;
padding: 15px 0;
background-color: lightblue;
}
.wrap {
display: flex;
flex-flow: column;
flex-grow: 1;
}
.wrap:nth-child(2){
align-items: flex-end;
}
.box {
background-color: tomato;
box-sizing: border-box;
border: 1px solid #C4C4C4;
height: 100px;
width: 90%;
margin-top: 15px;
}
.box1, .box4{
margin-top: 0;
}
.box1, .box5 {
height: 20px;
}
<div class="outer">
<div class="wrap">
<div class="box box1">box1</div>
<div class="box box2">box2</div>
<div class="box box3">box3</div>
</div>
<div class="wrap">
<div class="box box4">box4</div>
<div class="box box5">box5</div>
<div class="box box6">box6</div>
</div>
</div>
You could instead use a CSS grid layout depending on your browser support requirements.
Great resource on CSS Grid: https://css-tricks.com/snippets/css/complete-guide-grid/
Browser support: https://caniuse.com/#feat=css-grid
.wrap {
display: grid;
background-color: lightblue;
grid-template-columns: 50% 50%;
grid-template-rows: repeat(14, 20px);
background-color: lightblue;
}
.box {
background-color: tomato;
box-sizing: border-box;
border: 1px solid #C4C4C4;
height: 100px;
width: 90%;
margin-top: 15px;
}
.box1 {
grid-row: 1/2;
}
.box2 {
grid-row: 1/5;
}
.box3 {
grid-row: 3/8;
}
.box4 {
grid-row: 7/8;
}
.box5, .box6 {
grid-row: 9/14;
}
.box1, .box4 {
height: 20px;
}
<div class="wrap">
<div class="box box1">box1</div>
<div class="box box2">box2</div>
<div class="box box3">box3</div>
<div class="box box4">box4</div>
<div class="box box5">box5</div>
<div class="box box6">box6</div>
</div>
Flex is always going to create a grid which is why you're seeing big spaces. Neither flex:row or flex:column will achieve the order that you have specified. Flex column will be able to achieve the layout that you're after like Ethan Vu suggested but that main caveat in that solution is a mandatory fixed height container which you may not want.
If you want a layout like that and don't want a fixed height then you can try using css columns or go for a javascript solution and use a 2 column masonry layout.

Left and right aligning flex items

I have 4 divs all in the same wrapper, I need the first 3 to align left (text) and the 4th to align right (an image).
There desired effect is as follows.
<one> <
<two> Four
<three> >
The html is basic literally just 4 divs in a wrapper and the css can just be display:flex on the wrapper.
I have partially achieved this by adding flex direction column onto the wrapper so all 4 then stack vertically but I need the 4th to align right as above.
Any help would be hugely appreciated.
Thanks
Using flexbox:
* {
box-sizing: border-box;
}
.container {
height: 500px;
border: 1px solid green;
display: flex;
flex-direction: column;
flex-wrap: wrap;
}
.item {
flex: 1;
padding: .5rem;
border: 1px dashed lightblue;
}
.one, .two, .three {
flex-basis: 33.333333%;
}
<div class="container">
<div class="item one">1</div>
<div class="item two">2</div>
<div class="item three">3</div>
<div class="item four">4</div>
</div>
Using css-grid:
* {
box-sizing: border-box;
}
.container {
height: 500px;
border: 1px solid green;
display: grid;
}
.item {
padding: .5rem;
border: 1px dashed lightblue;
}
.four {
grid-column: 2;
grid-row: 1 / span 3;
}
<div class="container">
<div class="item one">1</div>
<div class="item two">2</div>
<div class="item three">3</div>
<div class="item four">4</div>
</div>
.wrapper {
display: flex;
flex-direction: row;
}
<div class="wrapper">
<div>
<div>one</div>
<div>two</div>
<div>three</div>
</div>
<div>
<div>four</div>
</div>
</div>

adjust width of inner / child elements

I have a parent DIV which may have 1,2 or 3 child elements. If the parent has only one element the child should have 100% width, if 2 then each element should have 50% of available width and in case of 3 elements each child should have 33.3333% of width.
If you want to avoid tables and are fine with flexbox (which is supported by all modern browsers), your solution would be simply
.container {
display: flex;
align-items: stretch;
}
.container > * {
display: block;
width: 100%;
}
with
<div class="container">
<div></div>
<div></div>
<div></div>
</div>
(works fine for more elements as well).
/* solution */
.container {
display: flex;
align-items: stretch;
}
.container > * {
display: block;
width: 100%;
height: 100%;
}
/* for demo */
.container {
height: 30px;
}
.container > * {
height: 100%;
}
.container > :first-of-type {
background-color: red;
}
.container > :nth-of-type(2) {
background-color: green;
}
.container > :nth-of-type(3) {
background-color: blue;
}
<h3>one item</h3>
<div class="container">
<div></div>
</div>
<hr>
<h3>two items</h3>
<div class="container">
<div></div>
<div></div>
</div>
<hr>
<h3>three items</h3>
<div class="container">
<div></div>
<div></div>
<div></div>
</div>
Use table layout
.wrap{
border: 1px solid green;
min-height: 100px;
display: table;
width: 100%;
}
.wrap > div{
border: 1px solid red;
display: table-cell;
}
<div class="wrap">
<div class="box">div 1</div>
<div class="box">div 2</div>
<div class="box">div 3</div>
</div>

Resources