0

I have two divs,

<div class="right"></div> 
<div class="left"></div>

In that order. For those wondering why I have ordered the HTML elements as such, check this question. The right div is of a fixed width along with the CSS property; float:right; So when the page is resized, the left div expands to take up the rest of the page.

However, at a certain width, I want both divs to be 100% wide, but stacked such that the right div is below the left div.

I realise this is to do with the ordering of the html elements, but is there a way to make this work? I tried the solution from this thread, but it doesn't seem to work.

I have a fiddle here.

EDIT:

Ok, so I discovered the answer. I was missing a parent container div which needed display:table; Now it works beautifully.

<div class="container">
<div class="right"></div>
<div class="left"></div>
</div>

CSS

 .container {
     display:table;
}

(Although I can't get it to work in the fiddle...)

So here is a CSS only solution if anyone needs it in future.

Community
  • 1
  • 1
myol
  • 8,857
  • 19
  • 82
  • 143
  • Is there a lot of content inside of the .right div? If not you can just add another .right after the .left, show/hide it when needed in your media query – Huangism Jul 30 '14 at 17:03
  • 1
    Have you tried taking a look at Bootstrap's pull and push classes? You might be able to gain some inspiration from those: http://getbootstrap.com/css/#grid-column-ordering – Jason Jul 30 '14 at 17:18
  • Let me know if my solution suits you. There is always more than one way to implement anything. :) – Alessandro Incarnati Jul 30 '14 at 17:25
  • @BootstrapThemer, nope, the goal is to have the div which is **first** show up second. You just switched the two divs. – jcaron Jul 30 '14 at 17:25
  • @jcaron I don't see why BootstrapThemer's solution doesn't solve the problem. It would seem that myol's problem only occurs because of the order which the elements were placed. Unless there was a specific reason why reordering the elements isn't possible, BootstrapThemer's answer looks legit. Why invent some convoluted answer to a problem that could easily be avoided? – Jason Jul 30 '14 at 17:33
  • @Jason, the whole point of the question is to be able to change the order the divs are displayed. The OP might not have any control over the HTML generation but only the CSS. If you can reorder the divs, the answer is of course trivial. – jcaron Jul 30 '14 at 17:35
  • 1
    Yes, but he can since the first answer requires a .main wrapper. Plus, why in the html would you have the stuff that least important first? – Christina Jul 30 '14 at 17:45
  • 1
    @jcaron as BootstrapThemer pointed out, the OP clearly has control over the HTML generated because he is able to place a wrapper around the divs. Also, if we were to follow the strict directions given by the OP (as you suggested), my answer would be the only legit one that doesn't involve `display:table` hacks. – Jason Jul 30 '14 at 17:52
  • @BootstrapThemer: the wrapping container may already be there. In the worst case, it's the body. The flex box solutions as well as mine do also work while actually answering the OP's question. – jcaron Jul 31 '14 at 06:37
  • I have edited the question to inform people why I ordered the HTML elements that way. I used that method because I want to support IE and mobile browsers. The CSS calc property is not yet widely supported on mobile. – myol Jul 31 '14 at 10:18
  • @myol : I realized, on the second go at the answer, that the 100% fluid/fixed was the reason why you had that div order. With content-box sizing, that was the way to do it. My answer didn't use flexbox, display:table, or calc, transforms, it used box-sizing:border-box and a negative margin, supported stuff in IE8 and current browsers. Plus, the more important content is first in the html, not for SEO but for logic, though these days, hardly anyone cares about that. http://jsbin.com/cizox/1/edit http://media.crossbrowsertesting.com/users/50267/snapshots/z65acffb9385ce671df4.png – Christina Jul 31 '14 at 15:36

8 Answers8

1

One solution could be to use transform: scaleY(-1); and a wrapper.

Try with this code if it suits your needs:

HTML

<div class="wrapper">
<div class="right"></div> 
<div class="left"></div>
</div>

CSS

.left {
    overflow: hidden;
    min-height: 50px;
    border: 2px dashed blue;    
}

.right {
    float: right;
    width: 250px;
    min-height: 50px;
    margin-left: 10px;
    border: 2px dashed red;
}

@media only screen and (max-width: 600px) {
    .right {       
        float: left;
        width: 100%;
    }
    .left {       
        float: left;
        width: 100%;
    }
    .wrapper{
        width:100%;
        position: absolute;
        float: left;
        -webkit-transform: scaleY(-1);
        transform: scaleY(-1);
    }
    div.wrapper > div {
    position: relative;
    float: right;
    display: block;
    min-height: 50px;
    -webkit-transform: scaleY(-1);
    transform: scaleY(-1);
    }

}

Ps. I changed the rgb values to red and blue for better readability.

Check this DEMO:

http://jsfiddle.net/EXn6Z/11/

Alessandro Incarnati
  • 7,018
  • 3
  • 38
  • 54
1

You can use the display: table property. This does not support borders though

DEMO http://jsfiddle.net/EXn6Z/12/

@media only screen and (max-width: 600px) {
    .main {
        display: table;
    }
    .right {
        display: table-footer-group;
        float: none;
        width: 100%;
    }
    .left {
        display: table-header-group;
        float: none;
        width: 100%;
    }
}
Kevin Lynch
  • 24,427
  • 3
  • 36
  • 37
  • Yea, I discovered this after I posted the question. You got the fiddle to work too so +1. Thanks. – myol Jul 30 '14 at 17:30
1

You can (ab)use the power of display: table-caption to make an element appear above others even if it comes after in your HTML code though the other element must have display: table-row here thus no border or background on it and you'd have to add an extra div if you want a background or border on .left.

Codepen: http://codepen.io/anon/pen/vdbcB

Relevant CSS (MQ):

@media only screen and (max-width: 600px) {
  .right {
    display: table-row;
    float: none;
    width: 100%;
    margin-left: 0;
  }
  .left {
    display: table-caption;
    overflow: visible;
    width: 100%;
  }
}

If you can add a parent div with display: table then you don't have to force display: table-row on div.right (better option imho). This is due to anonymous boxes created by browsers when the perfect serie of 3 elements table > row > cell isn't exactly there... Complex stuff.

Codepen: http://codepen.io/anon/pen/eIfmn

HTML:

<div class="table-like">
  <div class="right">On right or below Lorem ipsum dolor sit amet, consectetur adipisicing elit. Architecto error maiores quos incidunt quaerat atque amet perspiciatis ad quae maxime, possimus tempore rerum laudantium, fugit laborum sint consequatur eveniet veniam?</div> 
  <div class="left">On left or above</div>
</div>

Relevant CSS (MQ):

@media only screen and (max-width: 600px) {
  .table-like {
    display: table;
    width: 100%;
  }
  .right {
    float: none;
    width: auto;
    margin-left: 0;
  }
  .left {
    display: table-caption;
    overflow: visible;
    width: auto;
  }
}

Even if these 2 options work, it causes problems and I'd advise you against using them except if really really you don't have any other choice (like complex layout on desktop and tablet and now comes mobile resolution - in desktop first - and your HTML order is already set or your client won't let change HTML)

Problem that is accessibility related: WCAG 2.0 Technique H4: Creating a logical tab order through links, form controls, and objects

FelipeAls
  • 21,711
  • 8
  • 54
  • 74
0

You might not like this one because it involves jQuery, but overall it's pretty simple:

$(window).resize(function(){
    if($(window).width() <= 600) {
        $('.right').before($('.left'));
    } else {
        $('.right').after($('.left'));
    }
});

Fiddle: http://jsfiddle.net/LimitedWard/6ZE3B/

This technique avoids having unnecessary/duplicate elements.

This technique is also not a hack (unlike other answers that use display:table).

Note: there are ways of making this more efficient, but this should get the job done just fine.

Jason
  • 1,081
  • 10
  • 24
  • One benefit of this method is that it actually moves the element within the HTML rather than moving it using some positioning hacks. This means that if the user tries highlighting text in both divs, the highlight occurs in the correct order. – Jason Jul 30 '14 at 17:25
0

If the two divs are alone in a container (which may be body), then it's just a matter of sticking the first div to the bottom (using position: absolute and bottom: 0) and adding a margin-bottom to the second div. All of this in the relevant media-query section of course.

Caveat: if both divs have a variable height it might be quite a bit more difficult.

HTML:

<div id="container">
  <div id="right">nav</div>
  <div id="left">content</div>
</div>

CSS:

*
{
    box-sizing: border-box;
}
#container
{
    border: solid 2px green;
}
#left
{
    border: solid 2px red;
    min-height: 50px;
}

#right
{
    border: solid 2px blue;
    min-height: 50px;
}

@media (min-width: 600px)
{
    #left
    {
        margin-right: 200px;
    }
    #right
    {
        float: right;
        width: 200px;
    }
}
@media (max-width: 599px)
{
    #container
    {
        position: relative;
    }
    #left
    {
        margin-bottom: 50px;
    }
    #right
    {
        position: absolute;
        width: 100%;
        bottom: 0;
    }
}

fiddle: http://jsfiddle.net/zqDN7/

jcaron
  • 17,302
  • 6
  • 32
  • 46
0

Flexbox layout can be horizontal or vertical and will let you rearrange the order of children of a container at will.

Codepen: http://codepen.io/anon/pen/FnLhu

HTML:

<div class="small-flex small-flex-v">
  <div class="right small-ml0 small-wauto">On right or below</div> 
  <div class="left small-flex-start">On left or above</div>
</div>

Relevant CSS (MQ with classes prefixed by .small-):

@media only screen and (max-width: 600px) {
  .small-flex {
    display : -webkit-box;
    display : -moz-box;
    display: -ms-flexbox;
    display : -webkit-flex;
    display : flex;
  }
  .small-flex-v {
    -webkit-box-orient: vertical;
    -moz-box-orient: vertical;
    -webkit-flex-direction: column;
    -ms-flex-direction: column;
    flex-direction: column;
  }
  .small-flex-start {
    -webkit-box-ordinal-group: -1;
    -moz-box-ordinal-group: 0;
    -ms-flex-order : -1;
    -webkit-order : -1;
    -moz-order : -1;
    order : -1;
  }
}

This is my second answer to this question, with no table-caption trick.
Advantage over display: table-caption or @Victor's solution with table-*-group: no problem with borders and/or backgrounds on these elements
Drawback: compatibility is IE9+ when display: table-* is IE8+

FelipeAls
  • 21,711
  • 8
  • 54
  • 74
0

This is a solution with display: flex usage:

.wrap {
    display: flex;
    flex-flow: row wrap;
}

.left {
    min-height: 50px;
    border: 2px dashed #f0f;
    order: 1;
    flex-grow: 1;

}

.right {
    min-height: 50px;
    border: 2px dashed #00f;
    order: 2;
    width: 200px;
    margin-left: 10px;
}

@media only screen and (max-width: 600px) {
   .right,
   .left {
    flex: 1 100%;
    margin: 0;
  }
}

for a markup like this:

<div class="wrap">
  <div class="right">right</div>
  <div class="left">left</div>
</div>

An example: http://jsfiddle.net/RVk9Q/1/

Don't forget to use the needed prefixes

Vangel Tzo
  • 8,885
  • 3
  • 26
  • 32
-1

Add another div where you need it and then use the display to hide/show the correct one.

HTML:

<div class="right-large"></div> 
<div class="left"></div>
<div class="right-mobile"></div>

CSS:

.left {
    overflow: hidden;
    min-height: 50px;
    border: 2px dashed #f0f
}

.right-large, .right-mobile {
    float: right;
    width: 250px;
    min-height: 50px;
    margin-left: 10px;
    border: 2px dashed #00f
}

.right-mobile{
    display: none;
}

@media only screen and (max-width: 600px) {
    .right-large{
        display: none;
    }
    .right-mobile {
        display: block;
        float: right;
        width: 100%;
    }
}

JSFIDDLE

Jmh2013
  • 2,625
  • 2
  • 26
  • 42