Flex box Responsive Layout with Left and Right Container - html

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

Related

Flex-direction column not working as expected [duplicate]

This question already has answers here:
Force flex item to span full row width
(2 answers)
Closed 3 years ago.
I have the following markup:
<div class="container">
<div class="logo"></div>
<div class="search"></div>
<div class="button"></div>
</div>
CSS (desktop):
.container {
display: flex;
}
On a desktop view they're displayed in a row, like that:
But on mobile view, i want them to re-reorder:
I've tried the following styles:
// here's media query for mobile devices
.container {
flex-direction: column;
flex-wrap: wrap;
align-items: stretch // so my items would be filling width
}
.logo {
order: 1;
flex: 1 0 50%;
}
.search {
order: 2;
flex: 0 1 100%;
}
.button {
order: 1;
flex: 1 0 50%;
}
But my results are:
Is this even possible with a flexbox?
You should look into "flex-grow" which allows flex items to grow if necessary in order to take up as much space as is available in its container. If all flex-items (in your case: .logo, .search, .button) have a flex-grow value of 1, the remaining space in .container will be distributed to its children equally.
Also, you should use
flex-direction: row;
in your case if you want them to stretch horizontally
Check out this fiddle for reference! https://jsfiddle.net/hgs5w19y/2/
You need to use flex-grow (great resource for understanding flexbox: https://css-tricks.com/snippets/css/a-guide-to-flexbox/)
HTML
<div class="container">
<div class="logo">Logo</div>
<div class="search">Search</div>
<div class="button">Button</div>
</div>
CSS
.container {
background-color: #ccc;
display: flex;
width: 300px;
flex-wrap: wrap;
text-align: center;
}
.container > div {
background-color: grey;
margin: 10px 20px;
padding: 10px 20px;
}
.logo {
order: 1;
flex-grow: 1;
}
.search {
order: 2;
flex-grow: 2;
}
.button {
order: 1;
flex-grow: 1;
}
No need of direction nor so many rules, just set a breakpoint and reset .search behavior
.container {
display: flex;
flex-wrap: wrap;
}
.container>div {
flex: 1;
}
div.search {
order: 1;
flex-basis: 100%;
}
#media screen and (min-width:731px) {
div.search {
order: 0;
flex: 1
}
}
/* demo purpose */
.container {
background: gray;
}
.container>div {
padding: 1em;
margin: 1em;
background: lightgray;
}
.container>div:before {
content: attr(class);
color: black;
}
<div class="container">
<div class="logo"></div>
<div class="search"></div>
<div class="button"></div>
</div>
breakpoint value is to be updated to yours (here set at 731 for the demo) , to see behavior, run the snippet in full page, or play with the demo https://codepen.io/gc-nomade/pen/mYXZdY

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>

Changing stack order between different rows flexbox

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>

Flexbox Layout Query, Rows to Columns

I am trying to achieve a flexbox based transition from this (mobile):
To this (desktop):
However I am struggling to stack the two side panels vertically, my own code generates the main, search and other in a single row. I have not inserted webkit code for the sake of brevity.
Code:
p {
padding: 10px;
}
.flex-container {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.header {
flex: 1 0 100%;
background-color: pink;
}
.search {
flex: 1 100%;
background-color: yellow;
}
.main {
flex: 1 100%;
background-color: lightblue;
}
.other {
flex: 1;
background-color: Red;
}
#media (min-width: 600px) {
.flex-container {} .search {
flex: 1 0;
order: 2
}
.main {
flex: 3 0;
order: 1;
}
.other {
flex: 1 0;
order: 3
}
}
<div class="flex-container">
<div class="header">
<p>header</p>
</div>
<div class="search">
<p>search</p>
</div>
<div class="main">
<p>main</p>
</div>
<div class="other">
<p>other</p>
</div>
</div>
jsFiddle: https://jsfiddle.net/azizn/d2pmdvc4/
The problem here is that you can't really do that with Flexbox if your main elements (#main, #search and #other) are siblings unless you know the fixed height value of #search (hacky solution with position: absolute):
#header, .flex div {
padding: 1em;
box-sizing: border-box;
border: 1px solid red;
margin-bottom: 1em; }
.flex {
display: flex;
flex-direction: column;
position: relative; }
#main { min-height: 300px; order: 2; }
#other { order: 3; }
/* desktop version */
#media (min-width:768px) {
.flex { flex-direction: row; flex-wrap: wrap; }
#main { width: 60%; }
#search { order: 2; width: 40%; height: 100px }
#other { width: 40%; position: absolute; top: 100px; right: 0; }
}
<div id="header">header</div>
<div class="flex">
<div id="main">main</div>
<div id="search">search</div>
<div id="other">other</div>
</div>
jsFiddle: https://jsfiddle.net/azizn/uhwzyr9b/
So logically you could try to wrap #search and #other inside another container but then you couldn't position #content between them because Flexbox can alter order of siblings only... The only workaround for that is probably JavaScript.
Edit: You can achieve your layout by using good old floats instead of Flexbox:
#header, #main, #search, #other {
padding:1em;
box-sizing:border-box;
border:1px solid red;
margin-bottom:1em;
}
#main { min-height: 300px; }
#media (min-width:768px) {
.container { overflow: auto; }
#main { width: 60%; float: left; }
#search { width:40%; float: right; }
#other { width:40%; float: right; }
}
<div id="header">header</div>
<div class="container">
<div id="search">search</div>
<div id="main">main</div>
<div id="other">other</div>
</div>
jsFiddle: https://jsfiddle.net/azizn/g5vxtbed/

How can I use flexbox to achieve a complex, responsive HTML layout?

I have looked into Flexbox to achieve a responsive layout like pictured below. Unfortunately I still have not figured out how to achieve a desktop layout like Figure 1 which rearranges itself to Figure 2 on viewports smaller than 414 pixel.
Figure 1 (desktop viewports)
Figure 2 (mobile viewports)
(scaled version)
Click here for image in original size
My code so far :
.flexbox {
display: -webkit-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
flex-wrap: wrap;
width: 100%;
margin: 0;
flex-direction: row;
}
.content-flexbox.one {
flex-basis: calc(66% - 1rem);
order: 2;
}
.content-flexbox.two {
flex-basis: calc(30% - 1rem);
order: 1;
}
.content-flexbox.three {
order: 3;
}
.content-flexbox.four {
order: 4;
}
.content-flexbox {
margin: 1rem;
-webkit-box-flex: 1;
-webkit-flex: 1;
-ms-flex: 1;
flex: 1;
}
#media only screen and (max-width: 959px) {
.flexbox {
-flex-direction: column;
padding-top: 1rem;
}
.content-flexbox {
margin: 1rem;
flex: 1;
flex-basis: 100%;
}
.content-flexbox.one {
flex-basis: 100%;
order: 1;
}
.content-flexbox.two {
flex-basis: 100%;
order: 2;
}
}
<div class="flexbox">
<div class="content-flexbox one">
<h1 class="posttitle">Lorem ipsum</h1>
<h2 class="subtitle">dolor sit amet</h2>
</div>
<div class="content-flexbox two">
<img src="http://placehold.it/300x300" />
</div>
<div class="content-flexbox three">
<span>Lorem ipsum dolor</span>
</div>
<div id="container-voting" class="content-flexbox four">
<div class="inner-container set">
<span>Lorem ipsum dolor</span>
</div>
<div class="inner-container get">
<span>Lorem ipsum dolor</span>
</div>
</div>
</div>
My question
Is this even possible with flexbox? Is there a better alternative more suited for this layout?
You’re looking for the experimental grid syntax. Flexbox is good for smaller, widget or component layout systems. Grid is for overall page layout, and it’s awesome.
Thing is, grid is only supported in IE, Edge, and the upcoming Safari browsers right now, but Firefox and Chrome support is allegedly just around the corner, and you can start trying it out today by enabling the right developer flag in those browsers.
Here is some sample code, but again, it will only work if your browser supports the new grid syntax.
*{
box-sizing: border-box;
}
.flexbox{
width: 320px;
display: grid;
grid-template-columns: calc(50% - 0.5ch) calc(50% - 0.5ch);
grid-gap: 1ch;
}
.one{
order: 2;
background-color: red;
}
.two{
grid-column: 1 / 3;
order: 1;
background-color: green;
}
.three{
order: 3;
background-color: pink;
}
.four{
display: grid;
grid-column: 1 / 3;
grid-gap: 1ch;
order: 4;
background-color: lavender;
}
.inner-container{
background-color: violet;
}
#media screen and (min-width: 500px){
.flexbox{
width: 500px;
grid-template-columns: calc(33.333% - 0.333ch) calc(33.333% - 0.333ch) calc(33.333% - 0.333ch);
}
.one{
grid-row: 1 / 3;
order: 1;
}
.two{
order: 2;
grid-column: 2 / 4;
}
.three{
order: 3;
}
.four{
grid-column: 3 / 4;
order: 4;
}
}
<div class="flexbox">
<div class="content-flexbox one">
<h1 class="posttitle">Lorem ipsum</h1>
<h2 class="subtitle">dolor sit amet</h2>
</div>
<div class="content-flexbox two">
<img src="http://placehold.it/300x300" />
</div>
<div class="content-flexbox three">
<span>Lorem ipsum dolor</span>
</div>
<div id="container-voting" class="content-flexbox four">
<div class="inner-container set">
<span>Lorem ipsum dolor</span>
</div>
<div class="inner-container get">
<span>Lorem ipsum dolor</span>
</div>
</div>
Although this question explicitly asked for a flexbox approach, there is another way to achive it using simple floats.
A media query allows to rearange the elements in the desired order on viewports less than 414px wide:
.wrap {
background: #d0d0d0;
padding: 1%;
}
.wrap:after {
content: '';
display: block;
clear: both;
}
.el {
float: left;
margin: 1%;
}
.el1 {
width: 31.33%;
padding-bottom: 31.33%;
background: #FF7676;
}
.el2 {
float: right;
width: 64.66%;
padding-bottom: 14.66%;
background: #C2FF76;
}
.el3 {
width: 31.33%;
padding-bottom: 14.66%;
background: #FF9BF7;
}
.el4 {
width: 31.33%;
padding-bottom: 6.33%;
background: #9BA4FF;
}
#media (max-width: 414px) {
.el2, .el4 {
width: 98%;
padding-bottom: 31.33%;
}
.el1, .el3 {
width: 48%;
padding-bottom: 48%;
}
}
<div class="wrap">
<div class="el el2"></div>
<div class="el el1"></div>
<div class="el el3"></div>
<div class="el el4"></div>
<div class="el el4"></div>
</div>
Note that I used padding-bottom to keep the aspect ratio of the elements in this example (more info in this answer).
I don't know what content you intend to put in the blocks but you will need to use absolute positionnig for it if you want to stick with the "padding technique". For plain text content, you can check this fiddle.
The problem is that, if you want to be able to rearrange all items, they must be flex items of the same flex container. But Flexbox does not provide any direct way to make an element occupy more than one flex line.
However, you can use multiple containers and display: contents:
The element itself does not generate any boxes, but its children and
pseudo-elements still generate boxes as normal. For the purposes of
box generation and layout, the element must be treated as if it had
been replaced with its children and pseudo-elements in the document
tree.
/* Desktop */
.container {
display: flex;
flex-wrap: wrap;
}
.container > * {
flex-grow: 1;
}
.item {
margin: 2px;
}
.column {
flex-direction: column;
}
.fill {
width: 100%;
}
/* Mobile */
#media (max-width: 414px) {
.container > .container {
display: contents;
}
.i2 {
order: -1;
}
.i4 {
width: 100%;
}
}
/* Pretty */
.i1 { background: #FF7676; }
.i2 { background: #C2FF76; }
.i3 { background: #FF9BF7; }
.i4 { background: #9BA4FF; }
<div class="container">
<div class="item i1">1</div>
<div class="container">
<div class="item i2 fill">2</div>
<div class="item i3">3</div>
<div class="container column">
<div class="item i4">4a</div>
<div class="item i4">4b</div>
</div>
</div>
</div>
The only problem is that display: contents is not widely supported yet, but you can see it working on Firefox.
I don't think this is possible to do with pure css, but you could use some js and change html structure on resize with wrapAll() and unwrap(). You also need to use media queries to change order and some css when window is < 414px.
$(window).on("resize", function() {
var windowW = $(window).width();
if (windowW < 414) {
if ($('.right, right-inner').length) $('.two, .four').unwrap();
if (!$('.top').length) $('.one, .two, .three').wrapAll('<div class="top"></div>');
} else {
if ($('.top').length) $('.one, .two, .three').unwrap();
if (!$('.right, .right-inner').length) {
$('.three, .four').wrapAll('<div class="right-inner"></div>');
$('.two, .right-inner').wrapAll('<div class="right"></div>');
}
}
}).resize();
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body,
html {
margin: 0;
padding: 0;
font-family: sans-serif;
}
.flexbox {
display: flex;
min-height: 100vh;
color: white;
font-size: 50px;
}
.one {
flex: 1;
background: #FF7676;
margin: 10px;
}
.right {
flex: 2;
display: flex;
flex-direction: column;
margin: 10px;
}
.two {
height: 40%;
display: flex;
margin-bottom: 20px;
margin-right: 10px;
}
.two img {
width: 100%;
margin: 0;
}
.right-inner {
display: flex;
flex: 2;
}
.three,
.four {
flex: 1;
}
.three {
background: #FF9BF7;
margin-right: 10px;
}
.four {
display: flex;
flex-direction: column;
}
.set,
.get {
background: #9BA4FF;
flex: 1;
margin: 5px;
}
.set {
margin-top: 0;
}
.get {
margin-bottom: 0;
}
#media(max-width: 414px) {
.flexbox {
flex-direction: column;
}
.flexbox > * {
flex: 1;
margin: 10px;
}
.get,
.set {
margin: 0;
margin-bottom: 10px;
}
.two {
order: -1;
flex: 0 0 100%;
margin-bottom: 0;
}
.two img {
height: 100px;
}
.one,
.three {
width: 50%;
margin: 0;
}
.one {
margin-right: 10px;
}
.top {
display: flex;
flex-wrap: wrap;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<div class="flexbox">
<div class="content-flexbox one">
<span class="posttitle">1</span>
</div>
<div class="right">
<div class="content-flexbox two">
<img src="http://placehold.it/300x300/C2FF76" />
</div>
<div class="right-inner">
<div class="content-flexbox three">
<span>3</span>
</div>
<div id="container-voting" class="content-flexbox four">
<div class="inner-container set">
<span>4a</span>
</div>
<div class="inner-container get">
<span>4b</span>
</div>
</div>
</div>
</div>
</div>
I see that you can make two containers with floats and like mentioned before use liquid style page with width %. If you aproche mobile viewport use media querys to declair breakpoints.