91

I'm trying to swap two divs' locations for responsive design (the site looks different depending on width of the browser/good for mobile).

Right now I have something like this:

<div id="first_div"></div>
<div id="second_div"></div>

But would it be possible to swap their placements to make it look like second_div is first, using CSS only? The HTML stays the same. I've tried using floats and stuff but it doesn't seem to work the way I want it to. I don't want to use absolute positioning because the heights of the divs are always changing. Are there any solutions, or is there just no way to do this?

Rory O'Kane
  • 29,210
  • 11
  • 96
  • 131
Dragonfly
  • 4,261
  • 7
  • 34
  • 60
  • Are you worried about IE8? (http://caniuse.com/#feat=css-mediaqueries) Try media queries. – Mooseman Jul 03 '13 at 18:45
  • 2
    possible duplicate of [What is the best way to move an element that's on the top to the bottom in Responsive design](http://stackoverflow.com/questions/17115995/what-is-the-best-way-to-move-an-element-thats-on-the-top-to-the-bottom-in-respo) – cimmanon Jul 03 '13 at 18:48
  • That's what I'm using right now for responsive design, but I have these the bottom div that needs to be first when its for mobile. – Dragonfly Jul 03 '13 at 18:48
  • 1
    It depends on how the `div`s are currently laid out. For example, the solution is very easy if `first_div` already has `float: left` and `second_div` has `float: right` – you would just need to reverse the `float`s’ directions. Other layouts would be harder to fix. Tell us the current layout. – Rory O'Kane Jul 03 '13 at 18:54
  • [2022 solution](https://stackoverflow.com/a/71772248/7910454) – leonheess Apr 06 '22 at 18:56

11 Answers11

144

Someone linked me this: What is the best way to move an element that's on the top to the bottom in Responsive design.

The solution in that worked perfectly. Though it doesn’t support old IE, that doesn’t matter for me, since I’m using responsive design for mobile. And it works for most mobile browsers.

Basically, I had this:

@media (max-width: 30em) {
  .container {
    display: -webkit-box;
    display: -moz-box;
    display: -ms-flexbox;
    display: -webkit-flex;
    display: flex;
    -webkit-box-orient: vertical;
    -moz-box-orient: vertical;
    -webkit-flex-direction: column;
    -ms-flex-direction: column;
    flex-direction: column;
    /* optional */
    -webkit-box-align: start;
    -moz-box-align: start;
    -ms-flex-align: start;
    -webkit-align-items: flex-start;
    align-items: flex-start;
  }

  .container .first_div {
    -webkit-box-ordinal-group: 2;
    -moz-box-ordinal-group: 2;
    -ms-flex-order: 2;
    -webkit-order: 2;
    order: 2;
  }

  .container .second_div {
    -webkit-box-ordinal-group: 1;
    -moz-box-ordinal-group: 1;
    -ms-flex-order: 1;
    -webkit-order: 1;
    order: 1;
  }
}

This worked better than floats for me, because I needed them stacked on top of each other and I had about five different divs that I had to swap around the position of.

Community
  • 1
  • 1
Dragonfly
  • 4,261
  • 7
  • 34
  • 60
  • 4
    Here's [an example](http://jsfiddle.net/5rd9xwsc/2/) of how you can use the flexbox method. – blimmer Dec 01 '14 at 23:31
  • Thank you for that example. I was able to edit it to accomplish my goal: http://jsfiddle.net/5rd9xwsc/73/ – Ryan Nov 29 '15 at 19:24
  • 1
    http://jsfiddle.net/5rd9xwsc/75/ is an even better example of what I was trying to do, which is: Images are always alternated with text, even when you resize the window. – Ryan Nov 29 '15 at 20:13
  • 1
    I love StackOverflow so much & that I was able to search my activity and find this post again. I updated the fiddle because http://jsfiddle.net/5rd9xwsc/82/ is even closer to what I wanted to do (in WordPress). – Ryan Feb 03 '16 at 20:42
  • Just as a heads up - this solution may look complicated or fragile at first glance, but it's actually blessedly simple. The vendor specific styles are what make it look "bulky." In my use case I didn't even need the vendor specific styles. Thanks for the lifesaver Dragonfly! – Tell Mar 04 '20 at 14:57
  • will it work if first_div and second_div aren't siblings? – Akmal Salikhov Oct 06 '22 at 10:09
44

The accepted answer worked for most browsers but for some reason on iOS Chrome and Safari browsers the content that should have shown second was being hidden. I tried some other steps that forced content to stack on top of each other, and eventually I tried the following solution that gave me the intended effect (switch content display order on mobile screens), without bugs of stacked or hidden content:

.container {
  display:flex;
  flex-direction: column-reverse;
}

.section1,
.section2 {
  height: auto;
}
Jason Awbrey
  • 889
  • 9
  • 11
34

This question already has a great answer but in the spirit of exploring all possibilities here is another technique to reorder dom elements whilst still allowing them to take up their space, unlike the absolute positioning method.

This method works in all modern browsers and IE9+ (basically any browser that supports display:table) it has a drawback that it can only be used on a max of 3 siblings though.

//the html    
<div class='container'>
    <div class='div1'>1</div>
    <div class='div2'>2</div>
    <div class='div3'>3</div>
</div>

//the css
.container {
   display:table;    
}
.div1 {
    display:table-footer-group;
}
.div2 {
    display:table-header-group;
}
.div3 {
    display:table-row-group;
}

This will reorder the elements from 1,2,3 to 2,3,1. Basically anything with the display set to table-header-group will be positioned at the top and table-footer-group at the bottom. Naturally table-row-group puts an element in the middle.

This method is quick with good support and requires much less css than the flexbox approach so if you are only looking to swap a few items around for a mobile layout for example then dont rule out this technique.

You can check out a live demo on codepen: http://codepen.io/thepixelninja/pen/eZVgLx

Ed Fryed
  • 2,160
  • 16
  • 14
  • The `width: 100%` line is useless: you can't give a width to a `display: table` element. – Clément Aug 25 '16 at 20:44
  • 1
    My bad. Its not in the example i did, must have accidentally crept in here. Regardless of whether its there the method still works though. :) – Ed Fryed Sep 19 '16 at 02:21
  • When dealing with form inputs, which usually have label above them, but are positioned before in the DOM (so we can target the labels based on the input's state), this is very helpful! Also great for floating labels. – Sơn Trần-Nguyễn Jun 14 '18 at 19:17
  • 1
    This is a really great non-flex way to do it. Even in 2019, we get 4% IE9 traffic. – secretwep Jun 29 '19 at 17:48
13

This solution worked for me:

Using a parent element like:

.parent-div {
    display:flex;
    flex-direction: column-reverse;
}

In my case I didn't have to change the css of the elements that I needed to switch.

pfmDev
  • 131
  • 1
  • 4
9

In some cases you can just use the flex-box property order.

Very simple:

.flex-item {
    order: 2;
}

See: https://css-tricks.com/almanac/properties/o/order/

Boris Yakubchik
  • 3,861
  • 3
  • 34
  • 41
8

enter image description here

Using CSS only:

#blockContainer {
  display: -webkit-box;
  display: -moz-box;
  display: box;
  -webkit-box-orient: vertical;
  -moz-box-orient: vertical;
  box-orient: vertical;
}

#blockA {
  -webkit-box-ordinal-group: 2;
  -moz-box-ordinal-group: 2;
  box-ordinal-group: 2;
}

#blockB {
  -webkit-box-ordinal-group: 3;
  -moz-box-ordinal-group: 3;
  box-ordinal-group: 3;
}
<div id="blockContainer">
  <div id="blockA">Block A</div>
  <div id="blockB">Block B</div>
  <div id="blockC">Block C</div>
</div>
leonheess
  • 16,068
  • 14
  • 77
  • 112
iqmaker
  • 2,162
  • 25
  • 24
5

Assuming Nothing Follows Them

If these two div elements are basically your main layout elements, and nothing follows them in the html, then there is a pure HMTL/CSS solution that takes the normal order shown in this fiddle and is able to flip it vertically as shown in this fiddle using one additional wrapper div like so:

HTML

<div class="wrapper flipit">
   <div id="first_div">first div</div>
   <div id="second_div">second div</div>
</div>

CSS

.flipit {
    position: relative;
}
.flipit #first_div {
    position: absolute;
    top: 100%;
    width: 100%;
}

This would not work if elements follow these div's, as this fiddle illustrates the issue if the following elements are not wrapped (they get overlapped by #first_div), and this fiddle illustrates the issue if the following elements are also wrapped (the #first_div changes position with both the #second_div and the following elements). So that is why, depending on your use case, this method may or may not work.

For an overall layout scheme, where all other elements exist inside the two div's, it can work. For other scenarios, it will not.

ScottS
  • 71,703
  • 13
  • 126
  • 146
2

Simple flexbox solution utilizing the order-property:

.container {
  display: flex;
  flex-direction: column;
}

.first {
  order: 3;
}

.second {
  order: 2;
}
<div class="container">
  <div class="first">First</div>
  <div class="second">Second</div>
  <div class="third">Third</div>
</div>
leonheess
  • 16,068
  • 14
  • 77
  • 112
1

assuming both elements have 50% width, here is what i used:

css:

  .parent {
    width: 100%;
    display: flex;
  }  
  .child-1 {
    width: 50%;
    margin-right: -50%;
    margin-left: 50%;
    background: #ff0;
  }
  .child-2 {
    width: 50%;
    margin-right: 50%;
    margin-left: -50%;
    background: #0f0;
  }

html:

<div class="parent">
  <div class="child-1">child1</div>
  <div class="child-2">child2</div>
</div>

example: https://jsfiddle.net/gzveri/o6umhj53/

btw, this approach works for any 2 nearby elements in a long list of elements. For example I have a long list of elements with 2 items per row and I want each 3-rd and 4-th element in the list to be swapped, so that it renders elements in a chess style, then I use these rules:

  .parent > div:nth-child(4n+3) {
    margin-right: -50%;
    margin-left: 50%;
  }
  .parent > div:nth-child(4n+4) {
    margin-right: 50%;
    margin-left: -50%;
  }
GZveri
  • 41
  • 3
0

Yesterday ran into the same problem. Grid areas worked out great in my case:

.content-body {
    display: grid;
    grid-template-areas: " left right ";
    grid-template-columns: 1fr 1fr;
}
.first_div {
    grid-area: right;
}
.second {
    grid-area: left;
}
Max Tuzenko
  • 1,051
  • 6
  • 18
0

You don't need anything fancy. Make a copy of your second div, and place it on top. Like this

<div id="second_div_copy"></div>
<div id="first_div"></div>
<div id="second_div"></div>

Give the second_div_copy display: none when you want first div to appear on top. Give the second_div_copy display: block, and the second_div display: none when you want the second div to appear on top.

It's really that simple. Or am I missing something ?

Rob
  • 11
  • 4
  • This is a 8yo post, so some things have changed since this time. Also, he doesn't want to add new div with js, but do everything in css – Elikill58 Dec 28 '21 at 09:46
  • Many things have changed, but you haven't understood what I meant. – Rob Dec 28 '21 at 10:51