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

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%;}
}

Related

How to make a specific div go on top of another div

I have two divs.
When resizing the browser, div 2 will go on the bottom, and div one will go on the top, something like the image below.
What I want is div 1 to go on the bottom and div 2 go on the top, basically the opposite of what it does. I know I can just put div 2 on the top in the html but I want the div 1 to stay on the left.
Current code:
.div1 {
width: 55%;
height: 80vh;
display: inline-block;
margin-right: 1.5vh;
min-width: 50vh;
}
.div2 {
width: 50vh;
height: 80vh;
display: inline-block;
}
<div class="div1">
</div>
<div class="div2">
</div>
Hope that makes sense, thx to everyone that helps in advance.
The simplest way is to make parent container as display: flex; and use flex-wrap: wrap-reverse;:
.div1 {
width: 55%;
height: 80vh;
display: inline-block;
margin-right: 1.5vh;
min-width: 50vh;
background-color: blue;
}
.div2 {
width: 50vh;
height: 80vh;
display: inline-block;
background-color: red;
}
.container
{
display: flex;
flex-wrap: wrap-reverse;
/* ignore below */
resize: both;
overflow: hidden;
border: 1px solid black;
padding: 1em;
}
<div class="container">
<div class="div1">
</div>
<div class="div2">
</div>
resize me
</div>
You can achieve this by combining two concepts: media queries and flexbox.
I've set the max-width of the screen size that the media query starts applying to 600px, but you can change this to whatever value (min or max) that you want. The switch in how the two divs render when in column-view is handled via flex-direction: column-reverse.
You'll need to wrap your divs in a parent container to apply them:
.container {
display: flex;
flex-direction: row;
}
#media screen and (max-width: 600px) {
.container {
flex-direction: column-reverse;
}
}
.div1 {
width: 55%;
height: 80vh;
display: inline-block;
margin-right: 1.5vh;
min-width: 50vh;
background: green;
}
.div2 {
width: 50vh;
height: 80vh;
display: inline-block;
background: orange;
}
<div class="container">
<div class="div1"></div>
<div class="div2"></div>
</div>
You can read up on the two concepts I mentioned above in more detail:
media queries
flexbox

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

Moving a flex item from inside a column of items to its own column

If I have a flex container with three children with flex-direction: column, and I want to move the middle child to the right while keeping the first and third child to the left, how would I do that?
Is flexbox even the correct approach or is something else more appropriate?
This is my attempt:
.container {
display: flex;
flex-flow: row wrap;
#media (max-width: 840px) {
flex-flow: column wrap;
}
}
.red,
.green,
.blue {
width: 50%;
#media (max-width: 840px) {
width: 100%;
}
}
.red {
background-color: red;
height: 100px;
}
.green {
background-color: green;
height: 300px;
}
.blue {
background-color: blue;
height: 100px;
}
<div class="container">
<div class="red"></div>
<div class="green"></div>
<div class="blue"></div>
</div>
http://codepen.io/dye/pen/mOeZma
It's close, but not quite there. When green div moves to the right, there's a big gap between red and blue.
Any advice would be appreciated. Thank you!
Let me start by saying I like flexbox. It can take some time to get your head around all the little things it can do.
If I understood the question I think this does what you want (you'll need to press the full-screen button to see it in all it's glory, as I included the less that 840px stuff).
body {
margin: 0
}
.container {
display: flex;
flex-wrap: wrap;
flex-direction: column;
height: 400px
}
.blue,
.green,
.red {
width: 50vw
}
.red {
height: 100px;
background: red
}
.green {
height: 200px;
order: 1;
background: green
}
.blue {
background: #00f;
height: 300px
}
#media (max-width: 840px) {
.container {
height: auto
}
.blue,
.green,
.red {
width: 100vw
}
.green {
order: 0
}
}
<div class="container">
<div class="red"></div>
<div class="green"></div>
<div class="blue"></div>
</div>
I've manually set the height of the container to trigger the wrapping, and I've giving green a positive order so it's at the bottom of the list. Though when it's small and all in one column I've taken the order away so it is in the middle again.
I hope this helps, and never give up on flexbox ;-)
The answer is no. Flexbox doesn't have the flexibility that you want especially when you are building a dynamic.
If this is static
.container {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-flow: row wrap;
-ms-flex-flow: row wrap;
flex-flow: row wrap;
}
.holder {
width: 50%;
}
.holder .red, .holder .blue {
width: 100%;
}
.red,
.green,
.blue {
width: 50%;
}
.red {
background-color: red;
height: 100px;
}
.green {
background-color: green;
height: 300px;
}
.blue {
background-color: blue;
height: 100px;
}
<div class="container">
<div class="holder">
<div class="red"></div>
<div class="blue"></div>
</div>
<div class="green"></div>
</div>
So, the answer might be in javascript.
I prefer to just use masonry.
http://masonry.desandro.com/
Instructions are straight-forward. It is easy to setup.
.green{
float: right;
}
.red,
.green,
.blue {
width: 50%;
display: inline-block;
}
.red {
background-color: red;
height: 100px;
}
.green {
background-color: green;
height: 300px;
}
.blue {
background-color: blue;
height: 100px;
}
<body>
<div class="container">
<div class="red"></div>
<div class="green"></div>
<div class="blue"></div>
</div>
</body>
Ive removed the flex box and float it instead. much simpler i think
Add order property to .green class.
.green {
background-color: green;
height: 300px;
order: 1;
}
and you can order all the elements as well.
.red {
background-color: red;
height: 100px;
order: 1;
}
.green {
background-color: green;
height: 300px;
order: 3;
}
.blue {
background-color: blue;
height: 100px;
order: 2;
}
Maybe you just should turn on flex for container only for max width: 840px? For higher resolutions you can make container display block and float first and third div to left and second to right, that's all.
.container {
#media (max-width: 840px) {
display: flex;
flex-flow: column wrap;
}
}
.red,
.green,
.blue {
width: 50%;
#media (max-width: 840px) {
width: 100%;
}
}
.red {
background-color: red;
height: 100px;
#media (min-width: 841px) {
float: left;
}
}
.green {
background-color: green;
height: 300px;
#media (min-width: 841px) {
float: right;
}
}
.blue {
background-color: blue;
height: 100px;
#media (min-width: 841px) {
float: left;
}
}
http://codepen.io/anon/pen/QGjegM
Neither of these directly answer your question but may be of use to those in the future who find their way here with similar questions..
1. On the possibility that you are wanting to keep the two left blocks the same height as the right (green) here is how you could do that (i added two wrappers, additional code)
note: the jquery is just for demonstration purposes
// the jquery is just to adjust height for vertical flex demonstration
$('adjustorator').click(function() {var heights = Array(100, 150, 200, 250, 300, 350, 450, 500);var height = heights[Math.floor(Math.random()*heights.length)]; $('.green').css('height', height)});
.container {
display: flex;
width: 100%;
}
.left, .right {
display: flex;
flex-wrap: wrap;
width: 50%;
}
.red, .blue, .green {
width: 100%;
}
.red {
background-color: red;
}
.blue {
background-color: blue;
}
.green {
background-color: green;
height: 400px;
}
// scaffolding below, ignore
body { position: relative; }
adjustorator { display: flex; position: fixed; bottom: 0; left: 50%;transform: translateX(-50%); padding: 4px 8px 2px 8px; font-variant: small-caps; color: hsla(0, 0%, 80%, 1); background-color: hsla(0, 0%, 20%, 1); border-radius: 5px 5px 0px 0px; cursor: pointer;}
adjustorator:hover { background-color: hsla(200, 40%, 40%, 1); }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class="container">
<div class="left">
<div class="red"></div>
<div class="blue"></div>
</div>
<div class="right">
<div class="green"></div>
</div>
</div>
<!-- scaffolding, ignore -->
<adjustorator>adjust height</adjustorator>
fiddle
https://jsfiddle.net/Hastig/42qzzhdu/
2 I'll also leave my original (non-) answer for those who come here in the future, looking for a solution to a similar question
align-self: flex-end; added to .green
fiddle
https://jsfiddle.net/Hastig/42qzzhdu/1/

How to wrap items in flexbox for smaller screens?

I'm trying to create a layout for different resize. I need to reach the result in these images here:
I have this code:
.container {
position: relative;
display: flex;
align-items: stretch;
}
.item {
background-color: black;
box-sizing: border-box;
padding: 20px;
flex: 2;
color: #fff;
}
.item:nth-child(2) {
background-color: grey;
flex: 1
}
.item:nth-child(3) {
background-color: green;
flex: 0.5;
}
#media screen and (max-width: 990px) {
.container {
height: auto;
display: table;
}
.item:nth-child(2) {
float: left;
}
.item:nth-child(3) {
float: right;
}
}
<section class="container">
<div class="item">
<h2>title1</h2>
<hr>You'll notice that even though this column has far more content in it, instead of the other columns ending early, they size themselves to meet the end of this column vertically.</div>
<div class="item">
<h2>title2</h2>
<hr>Normally, the only way to achieve this would be either a hack, or to set all boxes to min-height.
</div>
<div class="item">
<h2>title3</h2>
<hr>This is a column with not much content.
</div>
</section>
Here there's a codepen https://codepen.io/darudev/pen/pyBrzL
Problem is in 990px resize view, I don't find solution to create the same view as "mockup".
Is there someone that can help me or give me some suggestions?
Thank you.
You don't need the table and float properties in your code.
#media screen and (max-width: 990px) {
.container {
height: auto;
display: table;
}
.item:nth-child(2) {
float: left;
}
.item:nth-child(3) {
float: right;
}
}
The entire layout can be made with flexbox.
Here's the solution: When the screen resizes smaller than 990px, allow flex items to wrap and give the first item a 100% width, which forces the following items to the next line.
.container {
display: flex;
}
.item {
background-color: black;
box-sizing: border-box;
padding: 20px;
flex: 2;
color: #fff;
}
.item:nth-child(2) {
background-color: grey;
flex: 1;
}
.item:nth-child(3) {
background-color: green;
flex: 0.5;
}
#media screen and (max-width:990px) {
.container { flex-wrap: wrap; }
.item:first-child { flex-basis: 100%; }
}
<section class="container">
<div class="item">
<h2>title1</h2>
<hr>You'll notice that even though this column has far more content in it,
instead of the other columns ending early, they size themselves to meet the end
of this column vertically.</div>
<div class="item">
<h2>title2</h2>
<hr>Normally, the only way to achieve this would be either a hack, or to set
all boxes to min-height.</div>
<div class="item">
<h2>title3</h2>
<hr>This is a column with not much content.
</div>
</section>
revised codepen

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/