How do I mimic floats with flexbox? - css

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>

Related

How to have make a div take a minumum of 50% space but if no sibling is present take 100%

Simply put I have:
#Container {
display:'flex';
flex-wrap:'wrap';
}
.item {
flex-basis: '50%'
}
Scenario one:
<div id=Container>
<div class="item"></div> 33 %
<div class="item"></div> 33 %
<div class="item"></div> 33%
</div>
Scenario 2
<div id=Container>
<div class="item"></div> 50 %
<div class="item"></div> 50 %
</div>
scenario 3:
<div id=Container>
<div class="item"></div> 100 %
</div>
What I want in general tems is this to be fluid, the more items I put in the less space each item will have but if there is only 1 then I want it to take full space.
First you have to add display: flex; to #Container
#Container{
display: flex;
}
If you want to equally distribute the space between children then you can use flex property as
.item{
flex: 1;
}
Above CSS is minimum required styles, rest is for demo
#Container {
display: flex;
margin-top: 1rem;
}
.item {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
padding: 1rem;
}
.item:nth-child(1) {
background-color: red;
}
.item:nth-child(2) {
background-color: blueviolet;
}
.item:nth-child(3) {
background-color: aquamarine;
}
<div id="Container">
<div class="item">33 %</div>
<div class="item">33 %</div>
<div class="item">33 %</div>
</div>
<div id=Container>
<div class="item"> 50 % </div>
<div class="item"> 50 % </div>
</div>
<div id=Container>
<div class="item">100 %</div>
</div>
I think that this example could give you an idea of how to achieve what you want:
https://codepen.io/Eylen/pen/vYJBpMQ
.Container {
display: flex;
flex-wrap: wrap;
margin-bottom: 8px;
}
.item {
flex-grow: 1;
margin: 0 12px;
background: #f1f1f1;
}
Your main issue in the code that you gave, is that you're missing the flex item behaviour. I have just set that the item can grow to fill the space with the flex-grow:1.
You can make sure a flex child covers up the space if it can, you can provide flex-grow: 1
#Container {
display:flex;
}
.item {
width: 100%;
flex-grow: 1;
border: 1px solid;
text-align: center;
}
<h1> Scenario 1 </h1>
<div id=Container>
<div class="item">33 %</div>
<div class="item">33 %</div>
<div class="item">33%</div>
</div>
<h1> Scenario 2 </h1>
<div id=Container>
<div class="item">50 %</div>
<div class="item">50 %</div>
</div>
<h1> Scenario 3 </h1>
<div id=Container>
<div class="item">100 %</div>
</div>
Added a demo below.
$( document ).ready(function() {
$( "#add" ).click(function() {
$('#container').append('<div class="item"></div>');
});
$( "#remove" ).click(function() {
$('#container').children().last().remove();
});
});
#container {
width:100%;
height:500px;
background-color:#ebebeb;
display:flex;
flex-direction: column;
}
.item {
width:100%;
display: flex;
flex: 1;
border-bottom:1px solid #007cbe;
}
.item1 {
background:#007cbe;
}
.item2 {
background: #d60000;
}
.item3 {
background: #938412
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="container">
<div class="item item1">1</div>
<div class="item item2">2</div>
<div class="item item3">3</div>
</div>
<button id="add"> Add </div>
<button id="remove"> Remove </div>
Apply to the below CSS to fulfill your requirement.
#Container {
display: flex;
}
.item {
width: 100%;
min-height: 100px;
border: 1px solid;
}

Expand divs in column layout to match original height of parent

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>

How to set equal width for flex elements?

Why blocks .b have different width? How to set it equal?
.parent {
display: flex;
}
.parent>div {
flex: 1 1 auto;
}
.parent .b {
display: flex;
}
<div class="parent">
<div class="cell">
<div class="b"></div>
</div>
<div class="cell">>
<div class="b"></div>
</div>
<div class="cell">>
<div class="b"></div>
</div>
<div class="cell">>
<div class="b"></div>
</div>
<div>
Why blocks <div class="cell"> have different width?
Edit: use CSS grid and auto-fit:
.parent {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
}
.parent {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
}
.parent>div {
background-color: lightblue;
margin-left: 5px;
}
<div class="parent">
<div class="cell">
<div class="b"></div>
</div>
<div class="cell">>
<div class="b"></div>
</div>
<div class="cell">>
<div class="b"></div>
</div>
<div class="cell">>
<div class="b"></div>
</div>
</div>
Second re-edit**
First choice you can do is just set a flex on the parent element as this will only effect the first element below that, which in this case is the cell class, i will add a border on the cell class so you can see this in effect
<div class="parent">
<div class="cell">
<div class="b"></div>
</div>
<div class="cell">
<div class="b"></div>
</div>
<div class="cell">
<div class="b"></div>
</div>
<div class="cell">
<div class="b"></div>
</div>
<div>
.parent {
display: flex;
width: 70%;
}
.cell {
width: 20%;
height: 100px;
border: 1px solid orange;
}
here you can set the size of your parent width which will be the size across your screen, you can then set the width of the .cell childs and they will all then be the same, but only at a maximum of the parent
** second option you can do
Here is a simpler version, and i have added 3 different classes to show how you can choose the sizing you want
<div class="parent">
<div class="a"></div>
<div class="b"></div>
<div class="c"></div>
<div>
.parent {
display: flex;
width: 80%;
height: 100px;
}
.a {
flex: 40%;
border: 1px solid greenyellow;
}
.b {
flex: 20%;
border: 1px solid orange;
}
.c {
flex: 20%;
border: 1px solid blue;
}
Of course you can change them back and have them all be called the same class, and just assign one width and again they will all be the same... i hope this helps
I think they all are in same width. You need to use this css instead of the .parent>div selector
.cell {
flex: 1 1 auto;
}
.parent {
display: flex;
}
.cell {
flex: 1 1 auto;
}
.parent .b {
display: flex;
align-items: center;
justify-content: center;
}
.b {
height: 50px;
}
.cell:nth-child(1) {
background: red;
}
.cell:nth-child(2) {
background: yellow;
}
.cell:nth-child(3) {
background: green;
}
.cell:nth-child(4) {
background: teal;
}
<div class="parent">
<div class="cell">
<div class="b">hi</div>
</div>
<div class="cell">
<div class="b">hi</div>
</div>
<div class="cell">
<div class="b">hi</div>
</div>
<div class="cell">
<div class="b">hi</div>
</div>
<div>

Four items in two columns

I have this HTML
<div class='wrapper'>
<div class='item-1'>One</div>
<div class='item-2'>Two</div>
<div class='item-3'>Three</div>
<div class='item-4'>Four</div>
</div>
In CSS, is it possible for me to create a two column grid where item-1 and item-2 are in the first column, and item-3 and item-4 are in the second?
The heights of the divs are variable, so this is not strict 2x2 grid.
Basically, I'd like it to look like the example below, but I do not have the luxury of wrapping my items.
THANKS!
.wrapper {
display:grid;
grid-template-columns: 1fr 1fr;
}
<div class='wrapper'>
<div class='wrapper-1'>
<div class='item-1' style='height:100px;background-color:red;'>One</div>
<div class='item-2' style='height:80px;background-color:blue;'>Two</div>
</div>
<div class='wrapper-2'>
<div class='item-3' style='height:40px;background-color:orange;'>Three</div>
<div class='item-4' style='height:40px;background-color:green;'>Four</div>
</div>
</div>
The CSS for the wrapper is correct. The only thing you need to specify is from which line of the grid should each item start and end.
.item-1,
.item-2{
grid-column: 1/2;
width: 100%;
}
.item-3,
.item-4{
grid-column: 3/4;
width: 100%;
}
This should suit your needs. Note that the wrapper needs to have an explicit height in order for the columns to wrap, otherwise it's going to endlessly expand.
.wrapper {
display: flex;
flex-flow: column wrap;
height: 200px;
}
.item {
width: 50%;
}
.i-1 {
height: 100px;
background-color: green;
}
.i-2 {
height: 80px;
background-color: red;
}
.i-3 {
height: 40px;
background-color: blue;
}
.i-4 {
height: 40px;
background-color: yellow;
}
<div class='wrapper'>
<div class='item i-1'>One</div>
<div class='item i-2'>Two</div>
<div class='item i-3'>Three</div>
<div class='item i-4'>Four</div>
</div>

Verticaly centered equal height columns when some divs are nested?

I need equal height columns which vertically centre there content. When each column div is a direct descendant of a container this is easy to do with display table: http://codepen.io/anon/pen/XKzOrv
However I have nested divs. Is it still possible to achieve this layout without modifying my markup?
UPDATE - As I'm supporting IE9+ I cant use flexbox.
.cont {
width: 500px;
}
.depth1 {
width: 50%;
float: left;
display: table;
}
.depth2 {
display: table-cell;
width: 50%;
vertical-align: middle;
}
.a {
background: blue;
}
.b {
background: green;
}
.c {
background: orange;
}
.d {
background: grey;
}
<div class="cont">
<div class="depth1">
<div class="depth2 a">
A
</div>
<div class="depth2 b">
B
<br>Wrap
</div>
</div>
<div class="depth1">
<div class="depth2 c">
C
<br>
<br>
<br>Wrap
</div>
<div class="depth2 d">
D
</div>
</div>
</div>
Yes it is possible with Flexbox, just use display: flex on all child div elements except on .c and add align-items: center on .depth2
.cont {
width: 500px;
display: flex;
}
.depth1 {
width: 50%;
display: flex;
}
.depth2 {
width: 50%;
}
.depth2:not(.c) {
display: flex;
align-items: center;
}
.a {
background: blue;
}
.b {
background: green;
}
.c {
background: orange;
}
.d {
background: grey;
}
<div class="cont">
<div class="depth1">
<div class="depth2 a">
A
</div>
<div class="depth2 b">
B
<br>Wrap
</div>
</div>
<div class="depth1">
<div class="depth2 c">
C
<br>
<br>
<br>Wrap
</div>
<div class="depth2 d">
D
</div>
</div>
</div>

Resources