Changing stack order between different rows flexbox - html

Goodmorning. I am trying to change the stacking order in a flexbox situation, where there are 2 columns, but the first column contains a spot where the second column needs to be put in between. So when on mobile I need them to be ordered different than source order.
This is on large
col 1 col 2
----------==============
[A] [C]
[B]
Where A and B are in one column, and C is in the other
But on small breakpoint, it needs to be
[A]
[C]
[B]
Is this possible using just Flexbox?
So to clarify. The HTML structure is as such:
row
column
divA
divB
column
divC
Codepen example
.a { background-color: green; }
.b { background-color: red; }
.c { background-color: blue; }
.row {
display: flex;
flex-direction: column;
}
.column {
flex: 1;
}
#media (min-width: 768px) {
.row {
flex-direction: row;
}
}
<div class="row">
<div class="column">
<div class="a">A</div>
<div class="b">B</div>
</div>
<div class="column c">C</div>
</div>

Update
With original html and display: contents allows c to take full height without adding heights when in desktop. Also better solves original problem of how to change order of elements in two separate divs
.a {
background-color: green;
order: 1;
width: 100%;
}
.b {
background-color: red;
order: 3;
width: 100%;
}
.c {
background-color: blue;
order: 2;
}
.row {
width: 100%;
display: flex;
flex-direction: row;
flex-wrap: wrap; /* add this so you don't need the extra wrapper div */
}
.column {
width: 50%; /* start off width children being 50% width */
}
#media (max-width: 768px) {
.column {
width: 100%;
}
.column:first-child {
display: contents;
}
}
<div class="row">
<div class="column">
<div class="a">A</div>
<div class="b">B</div>
</div>
<div class="column c">C</div>
</div>
Original Answer
You can achieve what you want with media queries and order:
.a {
background-color: green;
order: 1;
}
.b {
background-color: red;
order: 3;
}
.c {
background-color: blue;
order: 2;
}
.row {
width: 100%;
display: flex;
flex-direction: row;
flex-wrap: wrap; /* add this so you don't need the extra wrapper div */
}
.row>div {
width: 50%; /* start off width children being 50% width */
}
#media (max-width: 768px) {
.row>div {
/* for small screens */
width: 100%;
}
}
<div class="row">
<div class="a">A</div>
<div class="b">B</div>
<div class="c">C</div>
</div>

Related

Flex box Responsive Layout with Left and Right Container

I have trouble with flexbox layout in mobile device. Desktop it looks okay
in Mobile view I want to display like below
first it should display "Overview" Box
second it should display "Payment" Box
3rd it should display "Activity" Box
.div1 {
box-sizing:border-box;
border:0.5px solid red;
}
.main-container {
height:100%;
display:flex;
}
.left-container {
flex:1 1 0;
}
.right-container {
flex:1 1 0;
display:flex;
//flex-direction:column;
}
.half-containers {
flex:1;
overflow:auto;
order: 1;
}
.half-containers-activity {
flex:1;
overflow:auto;
order: 0;
}
#include media-breakpoint-down(sm) {
.main-container {
flex-direction: row;
}
}
<div class="div1">
<div class="main-container">
<div class="left-container">
<div class="half-containers">
Overview
</div>
<div class="half-containers-activity">
Activity
</div>
</div>
<div class="right-container">
Payment
</div>
</div>
</div>
You can use the following method. The main thing here is to use display: contents; on .left-container to "neutralize" it, so that all three elements can be used "on one level" as flex children, applying according order parameters to them. All that in a media query, of course, to leave the desktop version unaltered.
.div1 {
box-sizing: border-box;
border: 0.5px solid red;
}
.main-container {
height: 100%;
display: flex;
}
.left-container {
flex: 1 1 0;
}
.right-container {
flex: 1 1 0;
display: flex;
//flex-direction:column;
}
.half-containers {
flex: 1;
overflow: auto;
order: 1;
}
.half-containers-activity {
flex: 1;
overflow: auto;
order: 0;
}
#media screen and (max-width: 700px) {
.main-container {
flex-direction: column;
}
.left-container {
display: contents;
}
.half-containers {
order: 0;
}
.right-container {
order: 1;
}
.half-containers-activity {
order: 2;
}
}
<div class="div1">
<div class="main-container">
<div class="left-container">
<div class="half-containers">
Overview
</div>
<div class="half-containers-activity">
Activity
</div>
</div>
<div class="right-container">
Payment
</div>
</div>
</div>
I should add that display: contents; is still regarded an "experimental value", but browser support is quite good already: https://caniuse.com/?search=display%3A%20contents

Responsive CSS: shift middle div rows to a separate column after reaching media query break point

I am using CSS media queries to create a responsive layout.
In my current HTML layout I use flexbox to align rows of divs:
<div id="page">
<div id="div-1">DIV 1</div>
<div id="div-2">DIV 2</div>
<div id="div-3">DIV 3</div>
<div id="div-4">DIV 4</div>
</div>
and CSS:
#page {
display: flex;
flex-direction: column;
align-items: center;
}
[id^="div-"] {
border: 1px solid #ccc;
margin-bottom: 10px;
width: 50vw;
}
#div-1 {
height: 50px;
}
#div-2 {
height: 70px;
}
#div-3 {
height: 150px;
}
#div-4 {
height: 100px;
}
Here is Jsfiddle for you to tinker with.
It is what I am after for a smaller viewports, but would like to switch things around on the next media query break point to have 2 middle divs to shift to a separate column on the right like this:
How do I achieve that? It is pretty obvious for me how to shift last few div rows to another column, but not sure how to tackle the middle rows...
Is there a way to do it by using flexbox or grid?
Another possible solution is to use the order-property in combination with Flexbox (drawback: you'll need a tiny bit of extra html and set the height of the #page container; advantages: flexible div heights and gap sizes):
#page {
display: flex;
flex-direction: column;
align-items: center;
}
[id^="div-"] {
border: 1px solid #ccc;
margin-bottom: 10px;
width: 50vw;
}
#div-1 {
height: 50px;
background: lightgreen;
}
#div-2 {
height: 70px;
background: lightyellow;
}
#div-3 {
height: 150px;
background: lightcoral;
}
#div-4 {
height: 100px;
background: lightblue;
}
#media (max-width: 1000px) {
#page {
flex-wrap: wrap;
height: 300px;
}
#small-screen-spacer {
order: 3;
align-self: stretch;
flex: 1 0 100%;
margin-right: 10px;
}
#div-1 {
order: 1;
}
#div-2 {
order: 4;
}
#div-3 {
order: 5;
}
#div-4 {
order: 2;
}
}
<div id="page">
<div id="div-1">DIV 1</div>
<div id="div-2">DIV 2</div>
<div id="div-3">DIV 3</div>
<div id="div-4">DIV 4</div>
<div id="small-screen-spacer"> </div>
</div>
The #small-screen-spacer will fill the entire available vertical space, so that all elements that come after the spacer (defined by the order property) are moved to the second column. Additionally you can set the desired gap between the two columns by setting margin-right on the spacer to your desired value.
Fiddle

is it possible to pull out a flex-item in the middle and stretch it to 100% width as a secondary row in html on resize?

Is it possible to pull out a flex-item in the middle and stretch it to 100% width as a second row in HTML on resize?
I have the follow flex-items wrapped in a flex-box
Item-A Item-B Item-C Item-D Item-E
<div class="d-flex flex-wrap">
<div>Item-A</div>
<div>Item-B</div>
<div>Item-C</div>
<div>Item-D</div>
<div>Item-E</Div>
</div>
On smaller devices, I want the Item-B to be pulled out of the row and display as a second row but inside the parent container. Is it possible to do with CSS flex?
Note: I am using bootstrap as CSS framework
Use flex-basis: 100% to make your item full width, and order: 1 to place it after all the other items in the container. In the snippet below I've set this to happen on devices smaller than 500px:
.flex-container {
display: flex;
flex-wrap: wrap;
}
.item {
flex: 1;
outline: 1px dashed tomato;
text-align: center;
}
#media only screen and (max-width: 500px) {
.item-b {
flex-basis: 100%;
order: 1;
}
}
<div class="flex-container">
<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>
You can use order and media queries to achieve the results.
* {
box-sizing: border-box;
}
.container {
display: flex;
flex-wrap: wrap;
}
.container > div {
border: solid 1px black;
width: 25%;
}
.item3 {
order: 5;
width: 100%;
flex-shrink: 0;
flex-grow: 1;
}
.item4 {
order: 3;
}
.item5 {
order: 4;
}
#media only screen and (min-width: 600px) {
.container {
flex-wrap: no-wrap;
}
.item3 {
order: 3;
flex-grow: 0;
}
.item4 {
order: 4;
}
.item5 {
order: 5;
}
}
<div class="container">
<div class="item1">Item1</div>
<div class="item2">Item2</div>
<div class="item3">Item3</div>
<div class="item4">Item4</div>
<div class="item5">Item5</div>
</div>

Two columns of equal height to reverse at breakpoint

I'm looking to make two columns of equal height that reverse their stacking at an 845px breakpoint. How should I code my css for regular view vs the 845px #media?
What are the benefits and or shortcomings of either method?
You can do it with the Flexbox:
.parent {
display: flex;
height: 300px;
}
.parent > .child-1 {
flex: 1;
background: red;
}
.parent > .child-2 {
flex: 1;
background: blue;
}
#media screen and (max-width: 845px) {
.parent {
flex-direction: column;
}
.parent > .child-1 {
order: 2;
}
}
<div class="parent">
<div class="child-1"></div>
<div class="child-2"></div>
</div>
This can be accomplished with flex and the order property. The basic idea is to stack the items, using their default DOM order (col 1 before col 2), then in a media query use the order property to swap the order so col 2 is to the left of col 1. Like this:
.container {
display: flex;
flex-direction: column;
}
.col {
flex: 1;
display: flex;
flex-basis: 200px;
flex-direction: column;
border-width: 1px;
border-style: solid;
justify-content: center;
text-align: center;
margin: 10px;
font-family: Arial;
}
.col--1 {
border-color: red;
color: red;
}
.col--2 {
border-color: blue;
color: blue;
}
#media screen and (min-width: 845px) {
.container {
flex-direction: row;
}
.col--1 {
order: 2;
}
.col--2 {
order: 1;
}
}
<div class="container">
<div class="col col--1">
COL 1<br/> DIV
</div>
<div class="col col--2">
COL 2<br/> DIV
</div>
</div>

Re-sizing and re-ordering elements between desktop and mobile layouts

I'd like to achieve the following with CSS only (left is mobile layout, right is desktop after breakpoint):
The challenge here obviously is that from a float point of view the element order changes: on mobile the green item is the second, but on desktop it's the first.
Is this possible to achieve with pure CSS? Possibility would be flex-box but I don't have enough experience to recreate this layout.
#container {
display: flex;
flex-direction: column;
flex-wrap: wrap;
height: 400px; /* 1 */
}
.box {
width: 50%;
}
.box1 {
background-color: lightgreen;
height: 400px;
}
.box2 {
background-color: orangered;
height: 200px;
}
.box3 {
background-color: aqua;
height: 200px;
}
#media (max-width: 600px) {
#container { height: auto; } /* 2 */
.box { width: 100%; }
.box2 { order: -1; } /* 3 */
}
/* purely decorative styles */
.box {
border: 1px solid #ccc;
display: flex;
justify-content: center;
align-items: center;
font-size: 1.5em;
}
* { box-sizing: border-box; }
<div id="container">
<div class="box box1"><span>1</span></div>
<div class="box box2"><span>2</span></div>
<div class="box box3"><span>3</span></div>
</div>
jsFiddle
Notes:
Without a fixed height in a column wrap container, flex items don't know where to wrap. So, for your larger screen, define a height which forces the second item to a new column.
Now you're in a mobile layout and wrapping is no longer necessary. The container needs to be twice the height of the desktop layout. Release the height.
Tell the red box to re-position itself first on the list. (The initial order value for flex items is 0.)
Yes you can do this if you can set fixed height on flex-container. You just need to use flex-direction: column and flex-wrap: wrap and then change order with media-queries.
.content {
display: flex;
flex-wrap: wrap;
flex-direction: column;
}
.a {
height: 200px;
background: #00FF02;
}
.b {
height: 100px;
background: red;
}
.c {
height: 100px;
background: blue;
}
#media(min-width:768px) {
.content {
height: 200px;
}
.content > div {
width: 50%;
}
}
#media(max-width:768px) {
.b {
order: -1;
}
}
<div class="content">
<div class="a">A</div>
<div class="b">B</div>
<div class="c">C</div>
</div>
There is also no-flex solution, fiddle (just replace media-query min-width with whatever breakpoint you consider phone width ends):
HTML:
<div class="div1"></div>
<div class="div2"></div>
<div class="div3"></div>
CSS:
div {
width: 50%;
}
.div1 {
background-color: red;
float: right;
height: 200px;
}
.div2 {
background-color: green;
float: left;
height: 400px;
}
.div3 {
background-color: blue;
float: right;
height: 200px;
}
#media (max-width: 500px) {
.div1, .div2, .div3 { width: 100%;}
}