312
votes

I'm making a responsive layout with a top fixed navbar. Underneath I have two columns, one for a sidebar (3), and one for content (9). Which on desktop looks like this

navbar
[3][9]

When I resize to mobile the navbar is compressed and hidden, then the sidebar is stacked on top of the content, like this:

navbar
[3]
[9]

I would like the main content at the top, so I need to change the order on mobile to this:

navbar
[9]
[3]

I found this article which covers the same points, but the accepted answer has been edited to say that the solution no applies to the current version of Bootstrap.

How can I reorder these columns on mobile? Or alternatively, how can I get the sidbar list-group into my expanding navbar?

Here is my code:

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">

<!-- Optional theme -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">

<!-- Latest compiled and minified JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>

<div class="navbar navbar-inverse navbar-static-top">
  <div class="container">
    <a href="#" class="navbar-brand">Brand Title</a>
    <button class="navbar-toggle" data-toggle="collapse" data-target=".navHeaderCollapse">
      <span class="icon-bar"></span>
      <span class="icon-bar"></span>
      <span class="icon-bar"></span>
    </button>
    <div class="collapse navbar-collapse navHeaderCollapse">

    <ul class="nav navbar-nav navbar-right"><!--original navbar-->
      <li class="active"><a href="#">Home</a></li>
      <li><a href="#">FAQ</a></li>
    </ul>

    </div>
  </div>
</div><!--End Navbar Div-->
    <div class="container">
  <div class="row">

    <div class="col-lg-3">
  <div class="list-group">
    <a href="#" class="list-group-item">
    <h4 class="list-group-item-heading">Lorem ipsum</h4>
    <p class="list-group-item-text">Lorem Ipsum is simply dummy text.</p></a>
  </div>
</div><!--end sidebar-->


<div class="col-lg-9">
  <div class="panel panel-default">
    <div class="panel-body">
      <div class="page-header">
     Main Content
    </div>
  </div>
</div><!--end main content area-->
7

7 Answers

503
votes

You cannot change the order of columns in smaller screens but you can do that in large screens.

So change the order of your columns.

<!--Main Content-->
<div class="col-lg-9 col-lg-push-3">
</div>

<!--Sidebar-->
<div class="col-lg-3 col-lg-pull-9">
</div>

By default this displays the main content first.

So in mobile main content is displayed first.

By using col-lg-push and col-lg-pull we can reorder the columns in large screens and display sidebar on the left and main content on the right.

Working fiddle here.

119
votes

Updated 2018

For the original question based on Bootstrap 3, the solution was to use push-pull.

In Bootstrap 4 it's now possible to change the order, even when the columns are full-width stacked vertically, thanks to Bootstrap 4 flexbox. OFC, the push pull method will still work, but now there are other ways to change column order in Bootstrap 4, making it possible to re-order full-width columns.

Method 1 - Use flex-column-reverse for xs screens:

<div class="row flex-column-reverse flex-md-row">
    <div class="col-md-3">
        sidebar
    </div>
    <div class="col-md-9">
        main
    </div>
</div>

Method 2 - Use order-first for xs screens:

<div class="row">
    <div class="col-md-3">
        sidebar
    </div>
    <div class="col-md-9 order-first order-md-last">
        main
    </div>
</div>

Bootstrap 4(alpha 6): http://www.codeply.com/go/bBMOsvtJhD
Bootstrap 4.1: https://www.codeply.com/go/e0v77yGtcr


Original 3.x Answer

For the original question based on Bootstrap 3, the solution was to use push-pull for the larger widths, and then the columns will show is their natural order on smaller (xs) widths. (A-B reverse to B-A).

<div class="container">
    <div class="row">
        <div class="col-md-9 col-md-push-3">
            main
        </div>
        <div class="col-md-3 col-md-pull-9">
            sidebar
        </div>
    </div>
</div>

Bootstrap 3: http://www.codeply.com/go/wgzJXs3gel

@emre stated, "You cannot change the order of columns in smaller screens but you can do that in large screens". However, this should be clarified to state: "You cannot change the order of full-width "stacked" columns.." in Bootstrap 3.

29
votes

Bootstrap 3 Answer

The answers here work for just 2 cells, but as soon as those columns have more in them it can lead to a bit more complexity. I think I've found a generalized solution for any number of cells in multiple columns.

Goals

Get a vertical sequence of tags on mobile to arrange themselves in whatever order the design calls for on tablet/desktop. In this concrete example, one tag must enter flow earlier than it normally would, and another later than it normally would.

Mobile

[1 headline]
[2 image]
[3 qty]
[4 caption]
[5 desc]

Tablet+

[2 image  ][1 headline]
[         ][3 qty     ]
[         ][5 desc    ]
[4 caption][          ]
[         ][          ]

So headline needs to shuffle right on tablet+, and technically, so does desc - it sits above the caption tag that precedes it on mobile. You'll see in a moment 4 caption is in trouble too.

Let's assume every cell could vary in height, and needs to be flush top-to-bottom with its next cell (ruling out weak tricks like a table).

As with all Bootstrap Grid problems step 1 is to realize the HTML has to be in mobile-order, 1 2 3 4 5, on the page. Then, determine how to get tablet/desktop to reorder itself in this way - ideally without Javascript.

The solution to get 1 headline and 3 qty to sit to the right not the left is to simply set them both pull-right. This applies CSS float: right, meaning they find the first open space they'll fit to the right. You can think of the browser's CSS processor working in the following order: 1 fits in to the right top corner. 2 is next and is regular (float: left), so it goes to top-left corner. Then 3, which is float: right so it leaps over underneath 1.

But this solution wasn't enough for 4 caption; because the right 2 cells are so short 2 image on the left tends to be longer than the both of them combined. Bootstrap Grid is a glorified float hack, meaning 4 caption is float: left. With 2 image occupying so much room on the left, 4 caption attempts to fit in the next available space - often the right column, not the left where we wanted it.

The solution here (and more generally for any issue like this) was to add a hack tag, hidden on mobile, that exists on tablet+ to push caption out, that then gets covered up by a negative margin - like this:

[2 image  ][1 headline]
[         ][3 qty     ]
[         ][4 hack    ]
[5 caption][6 desc ^^^]
[         ][          ]

http://jsfiddle.net/b9chris/52VtD/16633/

HTML:

<div id=headline class="col-xs-12 col-sm-6 pull-right">Product Headline</div>
<div id=image class="col-xs-12 col-sm-6">Product Image</div>
<div id=qty class="col-xs-12 col-sm-6 pull-right">Qty, Add to cart</div>
<div id=hack class="hidden-xs col-sm-6">Hack</div>
<div id=caption class="col-xs-12 col-sm-6">Product image caption</div>
<div id=desc class="col-xs-12 col-sm-6 pull-right">Product description</div>

CSS:

#hack { height: 50px; }

@media (min-width: @screen-sm) {
    #desc { margin-top: -50px; }
}

So, the generalized solution here is to add hack tags that can disappear on mobile. On tablet+ the hack tags allow displayed tags to appear earlier or later in the flow, then get pulled up or down to cover up those hack tags.

Note: I've used fixed heights for the sake of the simple example in the linked jsfiddle, but the actual site content I was working on varies in height in all 5 tags. It renders properly with relatively large variance in tag heights, especially image and desc.

Note 2: Depending on your layout, you may have a consistent enough column order on tablet+ (or larger resolutions), that you can avoid use of hack tags, using margin-bottom instead, like so:

Note 3: This uses Bootstrap 3. Bootstrap 4 uses a different grid set, and won't work with these examples.

http://jsfiddle.net/b9chris/52VtD/16632/

8
votes

October 2017

I would like to add another Bootstrap 4 solution. One that worked for me.

The CSS "Order" property, combined with a media query, can be used to re-order columns when they get stacked in smaller screens.

Something like this:

@media only screen and (max-width: 768px) {
    #first {
        order: 2;
    }
    #second {
        order: 4;
    }
    #third {
        order: 1;
    }
    #fourth {
        order: 3;
    }
}

CodePen Link: https://codepen.io/preston206/pen/EwrXqm

Adjust the screen size and you'll see the columns get stacked in a different order.

I'll tie this in with the original poster's question. With CSS, the navbar, sidebar, and content can be targeted and then order properties applied within a media query.

6
votes

In Bootstrap 4, if you want to do something like this:

    Mobile  |   Desktop
-----------------------------
    A       |       A
    C       |   B       C
    B       |       D
    D       |

You need to reverse the order of B then C then apply order-{breakpoint}-first to B. And apply two different settings, one that will make them share the same cols and other that will make them take the full width of the 12 cols:

  • Smaller screens: 12 cols to B and 12 cols to C

  • Larger screens: 12 cols between the sum of them (B + C = 12)

Like this

<div class='row no-gutters'>
    <div class='col-12'>
        A
    </div>
    <div class='col-12'>
        <div class='row no-gutters'>
            <div class='col-12 col-md-6'>
                C
            </div>
            <div class='col-12 col-md-6 order-md-first'>
                B
            </div>
        </div>
    </div>
    <div class='col-12'>
        D
    </div>
</div>

Demo: https://codepen.io/anon/pen/wXLGKa

3
votes

Starting with the mobile version first, you can achieve what you want, most of the time.

Examples here:

http://jsbin.com/wulexiq/edit?html,css,output

<div class="container">
      <h1>PUSH - PULL Bootstrap demo</h1>
    <h2>Version 1:</h2>

    <div class="row">

      <div class="col-xs-12 col-sm-5 col-sm-push-3 green">
        IN MIDDLE ON SMALL/MEDIUM/LARGE SCREEN
        <hr> TOP ROW XS-SMALL SCREEN
      </div>

      <div class="col-xs-12 col-sm-4 col-sm-push-3 gold">
        TO THE RIGHT ON SMALL/MEDIUM/LARGE SCREEN
        <hr> MIDDLE ROW ON XS-SMALL
      </div>

      <div class="col-xs-12 col-sm-3 col-sm-pull-9 red">
        TO THE LEFT ON SMALL/MEDIUM/LARGE SCREEN
        <hr> BOTTOM ROW ON XS-SMALL
      </div>

    </div>

    <h2>Version 2:</h2>

    <div class="row">

      <div class="col-xs-12 col-sm-4 col-sm-push-8 yellow">
        TO THE RIGHT ON SMALL/MEDIUM/LARGE SCREEN
        <hr> TOP ROW ON XS-SMALL
      </div>

      <div class="col-xs-12 col-sm-4 col-sm-pull-4 blue">
        TO THE LEFT ON SMALL/MEDIUM/LARGE SCREEN
        <hr> MIDDLE ROW XS-SMALL SCREEN
      </div>

      <div class="col-xs-12 col-sm-4 col-sm-pull-4 pink">
        IN MIDDLE ON SMALL/MEDIUM/LARGE SCREEN
        <hr> BOTTOM ROW ON XS-SMALL
      </div>

    </div>

    <h2>Version 3:</h2>

    <div class="row">

      <div class="col-xs-12 col-sm-5 cyan">
        TO THE LEFT ON SMALL/MEDIUM/LARGE SCREEN TOP ROW ON XS-SMALL
      </div>

      <div class="col-xs-12 col-sm-3 col-sm-push-4 orange">
        TO THE RIGHT ON SMALL/MEDIUM/LARGE SCREEN
        <hr> MIDDLE ROW ON XS-SMALL
      </div>

      <div class="col-xs-12 col-sm-4 col-sm-pull-3 brown">
        IN THE MIDDLE ON SMALL/MEDIUM/LARGE SCREEN
        <hr> BOTTOM ROW XS-SMALL SCREEN
      </div>

    </div>

    <h2>Version 4:</h2>
    <div class="row">

      <div class="col-xs-12 col-sm-4 col-sm-push-8 darkblue">
        TO THE RIGHT ON SMALL/MEDIUM/LARGE SCREEN
        <hr> TOP ROW XS-SMALL SCREEN
      </div>

      <div class="col-xs-12 col-sm-4 beige">
        MIDDLE ON SMALL/MEDIUM/LARGE SCREEN
        <hr> MIDDLE ROW ON XS-SMALL
      </div>

      <div class="col-xs-12 col-sm-4 col-sm-pull-8 silver">
        TO THE LEFT ON SMALL/MEDIUM/LARGE SCREEN
        <hr> BOTTOM ROW ON XS-SMALL
      </div>

    </div>

  </div>
0
votes

This is quite easy with jQuery using insertAfter() or insertBefore():

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

<script>
$('.right').insertBefore('left');
</script>

If you want to to set o condition for mobile devices you can make it like this:

<script>
  var $iW = $(window).innerWidth();
  if ($iW < 992){
     $('.right').insertBefore('.left');
  }else{
     $('.right').insertAfter('.left');
  }
</script>

example https://jsfiddle.net/w9n27k23/