Changing the order of columns in a responsive 3-column layout - html

I need to convert a 3-column fixed width layout to a responsive one and have been frying my brain trying to understand all the various ways people are going about this. The column widths are roughly 22% - 56% - 22% of the container div width. When displaying in a smartphone context, I want columns 1 and 3 to appear together side by side taking up 50% of the screen width each, then column 2 (the main content) to appear below at 100% of width.
Can anyone advise the best way to go about achieving this? Do I need to swap columns 2 and 3 around to get them to flow the way I want them to? Or is there another way that works as well without having to go through and change the markup of the entire site? I would like to use CSS only solutions if possible. Thanks.

You can do this with media queries and floats. Using float: left and float: right you just need to set up your HTML properly. The trick is to float column 1 to the left and two and three to the right with three coming before two in your html:
FIDDLE
HTML
<div class="wrapper">
<div class="one"></div>
<div class="three"></div>
<div class="two"></div>
</div>
CSS
.one{
float: left;
background: red;
width: 22%;
height:100px;
}
.two{
float: right;
background: blue;
width: 56%;
height:100px;
}
.three{
float: right;
background: green;
width: 22%;
height:100px;
}
#media only screen and (max-width: 300px){
.one{
width: 50%
}
.two{
width: 100%
}
.three{
width: 50%
}
}
UPDATE
As Crispy-George posted you could use flexbox but it does have limited browser support and basically doesn't work with IE 9 and below:
FLEXBOX EXAMPLE

If you have to maintain a strict order on your columns, like:
<div class='box box-1'>Small box</div>
<div class='box box-2'>Yeah, I'm the big box</div>
<div class='box box-3'>Even Smaller box</div>
you can use flexbox to change the order of these boxes on your desired screen resolutions, however I believe it has no support for lower than IE9, but if you dont have to support older browsers, check out the demo here.
The markup:
<div class='container'>
<div class='box box-1'>Small box</div>
<div class='box box-2'>Yeah, I'm the big box</div>
<div class='box box-3'>Even Smaller box</div>
</div>
And the css stuff:
.container{
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-flex-wrap: wrap;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
}
.box{
min-height: 200px;
font-size: 18px;
}
.box-1{
width: 25%;
background: red;
}
.box-2{
width: 60%;
background: teal;
}
.box-3{
width: 15%;
background: cyan;
}
#media all and (max-width: 768px){
.box-1{
-webkit-order: 1;
-ms-order: 1;
order: 1;
width: 50%;
}
.box-3{
-webkit-order: 2;
-ms-order: 2;
order: 2;
width: 50%;
}
.box-2{
-webkit-order: 3;
-ms-order: 3;
order: 3;
width: 100%;
}
}

Related

How can I accomplish this design with flexbox?

I'm trying to accomplish this design by using flexbox:
It's supposed to be a one page website.
.container {
display: flex;
}
.big {
flex: 2;
height: 70vh;
background: gray;
}
.small {
flex: 1;
height: 70vh;
background: gray;
}
<div class="container">
<div class="small">
</div>
<div class="smallest">
</div>
<div class="big">
</div>
</div>
I have no idea how to implement the "smallest" div to be 25% of the big, let alone make the "small" 75% of the big one.
Also the height really confuses me, I need them to always have the same height.
With flexbox you can wrap the small and the smallest into a separate div and use column flexbox on the left section.
I have no idea how to implement the "smallest" div to be 25% of the big
25% to 75% ratio means 1:3 ratio - and in flexbox language that is flex: 1 to the small element and flex: 3 to the big element.
Also the height really confuses me, I need them to always have the same height.
You can set the height of the container to the container element - your flexbox will fill to this height.
See demo below:
.container {
display: flex;
height: 70vh;
}
.big {
flex: 3;
background: gray;
margin-left: 5px;
}
.left {
flex: 1;
display: flex;
flex-direction: column;
}
.left .small {
background: gray;
flex: 3;
}
.left .smallest {
margin-top: 5px;
background: gray;
flex: 1;
}
<div class="container">
<div class="left">
<div class="small">
</div>
<div class="smallest">
</div>
</div>
<div class="big">
</div>
</div>

Flex order not working as expected

I have a nav element with 3 child divs, with widths 25%, 50%, and 25% respectively, also flexbox order 1,2 and 3 respectively. In mobile view, I want to shift the second element down to next row taking full-width and first and third to stay in the first row consuming 50% widths each. I changed the second element's order to 3 and width 100%, also third element's order to 2 and 50% width. However, it is still not working as expected. Is it possible to achieve something like that using flexbox?
I have included a sample code
<nav>
<div class="a">
A
</div>
<div class="b">
B
</div>
<div class="c">
C
</div>
</nav>
and CSS
nav{
display:flex;
flex-direction:row;
}
.a,.b,.c{
border:1px solid blue;
text-align: center;
}
.a{
width:25%;
order:1;
}
.b{
width:50%;
order:2;
}
.c{
width:25%;
order:3;
}
#media screen and (max-width: 400px){
.a{
width:50%;
}
.b{
width:100%;
order:3;
}
.c{
width:50%;
order:2;
}
}
or use the fiddle
basically this is what I'm trying to achieve.
default view
on mobile
I updated your fiddle: https://jsfiddle.net/s9v926g9/1/
There are 2 things you need to add:
Add flex-wrap: wrap; to the nav element
This will make the elements wrap to a next line, instead of spacing themselves out over the available width.
Set the box sizing
Adding
*{
box-sizing: border-box;
}
to your css will make sure the borders are not messing up your flex-wrap.
You need to set flex-wrap: wrap on flex container and then you can just change order on mobile size and set flex: 0 0 100% on b element. Demo
nav {
display: flex;
flex-wrap: wrap;
}
.a, .b, .c {
border: 1px solid blue;
text-align: center;
}
.a, .c {
flex: 1;
}
.b {
flex: 2;
}
#media screen and (max-width: 400px) {
.b {
order: 2;
flex: 0 0 100%;
}
}
<nav>
<div class="a">A</div>
<div class="b">B</div>
<div class="c">C</div>
</nav>

Place div1 under div4 when div1 html code is on top of div4 [duplicate]

I am working on a responsive site and came across an interesting problem. I have some divs side by side. There could be anywhere from 2 to 6 or so of them. When the screen isn't wide enough to show all the content properly, the divs stack vertically. Simple enough to do with CSS.
The problem is, I need them to be in a different order depending on the layout. This is easy to do with 2 or 3 divs (Changing divs order based on width), but significantly more challenging when you add a fourth.
I could use position: absolute; and manually set the position, however this causes the parent to shrink and not contain them properly.
To make this even more complicated, I can't use JavaScript.
Working with two columns:
(untested)
HTML:
<div id="container">
<div class="column-half column-half-2">
First div on mobile, right div on desktop
</div>
<div class="column-half column-half-1">
Second div on mobile, left div on desktop
</div>
</div>
CSS:
.container {
width: 80%;
max-width: 1200px;
margin: 0 auto;
padding-bottom: 20px;
position: relative;
}
.column-half {
display: table-cell;
padding: 25px;
vertical-align: top;
width: 40%;
}
.column-half-1 {
float: left;
}
.column-half-2 {
float: right;
}
HTML, with 4 columns:
<div id="container">
<div class="column-quarter column-quarter-3">
First div on mobile, third div on desktop
</div>
<div class="column-quarter column-quarter-2">
Second div on mobile, second div on desktop
</div>
<div class="column-quarter column-quarter-1">
Third div on mobile, first div on desktop
</div>
<div class="column-quarter column-quarter-4">
Fourth div on mobile, fourth div on desktop
</div>
</div>
This is doable in CSS thanks to the wonderful flexbox spec. Using the order and flex-flow properties, we can achieve what you want. Unprefixed, IE11 and all evergreen browsers will support this. IE10 prefixes -ms-order and doesn't support flex-flow.
The solution takes into consideration all the constraints you listed:
Have a list of elements in a given order displayed as a row.
When the window is too small, change them to display in a column.
Change the order of the elements when they are displayed in a column.
Because of the limitations of Stack Snippets, you'll need to view the demo in Full page mode, and resize your browser to see the effect.
.container div {
width: 100px;
height: 50px;
display: inline-block;
}
.one { background: red; }
.two { background: orange; }
.three { background: yellow; }
.four { background: green; }
.five { background: blue; }
#media screen and (max-width: 531px) {
.container { display: flex; flex-flow: column; }
.five { order: 1; }
.four { order: 2; }
.three { order: 3; }
.two { order: 4; }
.one { order: 5 }
}
<div class="container">
<div class="one">I'm first</div>
<div class="two">I'm second</div>
<div class="three">I'm third</div>
<div class="four">I'm fourth</div>
<div class="five">I'm fifth</div>
</div>
Alternatively, here is a JSFiddle demo.
You can also simply use flex-flow: column-reverse without the order property assigned to each div, if you are so inclined against verbose CSS. The same demo restrictions apply; view this demo in full screen and resize the browser window accordingly.
.container div {
width: 100px;
height: 50px;
display: inline-block;
}
.one { background: red; }
.two { background: orange; }
.three { background: yellow; }
.four { background: green; }
.five { background: blue; }
#media screen and (max-width: 531px) {
.container { display: flex; flex-flow: column-reverse; }
}
<div class="container">
<div class="one">I'm first</div>
<div class="two">I'm second</div>
<div class="three">I'm third</div>
<div class="four">I'm fourth</div>
<div class="five">I'm fifth</div>
</div>
It's worth pointing out that flex-flow is a shorthand property encompassing both flex-direction and flex-wrap properties.

Change div order with CSS depending on device-width

I am working on a responsive site and came across an interesting problem. I have some divs side by side. There could be anywhere from 2 to 6 or so of them. When the screen isn't wide enough to show all the content properly, the divs stack vertically. Simple enough to do with CSS.
The problem is, I need them to be in a different order depending on the layout. This is easy to do with 2 or 3 divs (Changing divs order based on width), but significantly more challenging when you add a fourth.
I could use position: absolute; and manually set the position, however this causes the parent to shrink and not contain them properly.
To make this even more complicated, I can't use JavaScript.
Working with two columns:
(untested)
HTML:
<div id="container">
<div class="column-half column-half-2">
First div on mobile, right div on desktop
</div>
<div class="column-half column-half-1">
Second div on mobile, left div on desktop
</div>
</div>
CSS:
.container {
width: 80%;
max-width: 1200px;
margin: 0 auto;
padding-bottom: 20px;
position: relative;
}
.column-half {
display: table-cell;
padding: 25px;
vertical-align: top;
width: 40%;
}
.column-half-1 {
float: left;
}
.column-half-2 {
float: right;
}
HTML, with 4 columns:
<div id="container">
<div class="column-quarter column-quarter-3">
First div on mobile, third div on desktop
</div>
<div class="column-quarter column-quarter-2">
Second div on mobile, second div on desktop
</div>
<div class="column-quarter column-quarter-1">
Third div on mobile, first div on desktop
</div>
<div class="column-quarter column-quarter-4">
Fourth div on mobile, fourth div on desktop
</div>
</div>
This is doable in CSS thanks to the wonderful flexbox spec. Using the order and flex-flow properties, we can achieve what you want. Unprefixed, IE11 and all evergreen browsers will support this. IE10 prefixes -ms-order and doesn't support flex-flow.
The solution takes into consideration all the constraints you listed:
Have a list of elements in a given order displayed as a row.
When the window is too small, change them to display in a column.
Change the order of the elements when they are displayed in a column.
Because of the limitations of Stack Snippets, you'll need to view the demo in Full page mode, and resize your browser to see the effect.
.container div {
width: 100px;
height: 50px;
display: inline-block;
}
.one { background: red; }
.two { background: orange; }
.three { background: yellow; }
.four { background: green; }
.five { background: blue; }
#media screen and (max-width: 531px) {
.container { display: flex; flex-flow: column; }
.five { order: 1; }
.four { order: 2; }
.three { order: 3; }
.two { order: 4; }
.one { order: 5 }
}
<div class="container">
<div class="one">I'm first</div>
<div class="two">I'm second</div>
<div class="three">I'm third</div>
<div class="four">I'm fourth</div>
<div class="five">I'm fifth</div>
</div>
Alternatively, here is a JSFiddle demo.
You can also simply use flex-flow: column-reverse without the order property assigned to each div, if you are so inclined against verbose CSS. The same demo restrictions apply; view this demo in full screen and resize the browser window accordingly.
.container div {
width: 100px;
height: 50px;
display: inline-block;
}
.one { background: red; }
.two { background: orange; }
.three { background: yellow; }
.four { background: green; }
.five { background: blue; }
#media screen and (max-width: 531px) {
.container { display: flex; flex-flow: column-reverse; }
}
<div class="container">
<div class="one">I'm first</div>
<div class="two">I'm second</div>
<div class="three">I'm third</div>
<div class="four">I'm fourth</div>
<div class="five">I'm fifth</div>
</div>
It's worth pointing out that flex-flow is a shorthand property encompassing both flex-direction and flex-wrap properties.

CSS flexbox - is there a better way to do this?

The result I'm looking for is one big block on the left, and then four small blocks on the right, and everything aligns.
I managed to do this in this fiddle but my solution has a couple of problems:
- it's not very clean in terms of code
- it's not responsive
HTML:
<div class="wrapper">
<div class="box big">ONE</div>
<div class="med-wrapper">
<div class="row-1">
<div class="box medium">TWO</div>
<div class="box medium">THREE</div>
</div>
<div class="row-2">
<div class="box medium">FOUR</div>
<div class="box medium">FIVE</div>
</div>
</div>
</div>
CSS:
.wrapper {
display: flex;
flex-direction: row;
flex-flow: row wrap;
justify-content: space-around;
height: 200px;
}
/* #media screen and (max-width: 768px) {
flex-direction: column
} */
.box {
background: #09f;
color: white;
padding: 1em;
margin: 5px;
text-align: center;
}
.big {
flex: 5;
}
.medium {
flex: 5;
height: 100px;
}
.med-wrapper {
display: flex;
}
Also, you might notice that I have set the flex on both .big and .medium to 5, because I want the total width of the big box and the total width of two medium boxes to be equal, but it didn't work.
Is there a better way to do this?
It's tricky to have everything to align without getting into a lot of constraints, but using flexbox wrapping in the column direction on the right part could work.
Here's a quick version that uses a flex-flow: column wrap on the right part (.med-wrapper) and gets rid of the wrapper element on the two column wrappers inside it -
<div class="wrapper">
<div class="box big">
ONE
</div>
<div class="med-wrapper">
<div class="box medium">TWO</div>
<div class="box medium">THREE</div>
<div class="box medium">FOUR</div>
<div class="box medium">FIVE</div>
</div><!-- /.med-wrapper -->
</div><!-- /.wrapper -->
...and then the CSS:
body {
font-family: 'calibri', sans-serif;
margin: 0;
}
.wrapper {
display: flex;
justify-content: space-around;
height: 200px;
}
.box {
background: #09f;
color: white;
padding: 1em;
margin: 0 5px;
text-align: center;
box-sizing: border-box;
}
.big {
flex: 1;
height: 100%;
}
.med-wrapper {
flex: 1;
display: flex;
height: 100%;
flex-flow: column wrap;
justify-content: space-between;
overflow: auto;
}
.medium {
/* exact sizing for the medium boxes (i.e. get it from main sizing.) */
flex: 0 0 auto;
/* adjust for margins: */
width: calc(50% - 10px);
height: calc(50% - 5px);
}
/* some theoretical adjustments for smaller screens */
#media screen and (max-width: 768px) {
/* switch the wrapper to column dir, and remove fixed height. */
.wrapper {
flex-direction: column;
height: auto;
}
/* just a min height for demo purposes. */
.big {
min-height: 200px;
}
/* Now we need to re-set a height on this one, if we
want to keep the 2x2 square thing. */
.med-wrapper {
margin-top: 10px;
height: 200px;
}
}
Live demo at http://jsbin.com/kasez/5/edit
I've used calc()for the size calculations to counter margins, but hey, if you're already depending on flexbox, you probably need a fallback anyway. :-)
It should work with just the one explicit height on the .wrapper element, but the rest of the items should adjust accordingly - the downside is that overflow handling gets hard.
This is, incidentally, the type of "2D" situation (vs flexbox's 1D) that Grid Layout is meant to help with, but it'll be a while before that is a viable option.