126

I have a fluid layout using Twitter's bootstrap, wherein I have a row with two columns. The first column has a lot of content, which I want to fill the span normally. The second column just has a button and some text, which I want to bottom align relative to the cell in the first column.

Here's what I have:

-row-fluid-------------------------------------
+-span6----------+ +-span6----------+
|                | |short content   |
| content        | +----------------+
| that           | 
| is tall        |    
|                |
+----------------+
-----------------------------------------------

Here's what I want:

-row-fluid-------------------------------------
+-span6----------+
|                |
| content        |
| that           | 
| is tall        | +-span6----------+    
|                | |short content   |
+----------------+ +----------------+
-----------------------------------------------

I've seen solutions that make the first span an absolute height, and position the second span relative to it, but a solution where I didn't have to specify the absolute height of my divs would be preferred. I'm also open to a complete rethink of how to achieve the same effect. I'm not married to this use of the scaffolding, it just seemed to make the most sense to me.

This layout as a fiddle:

http://jsfiddle.net/ryansturmer/A7buv/3/

Jeromy French
  • 11,812
  • 19
  • 76
  • 129
Ryan
  • 4,179
  • 6
  • 30
  • 31

10 Answers10

69

This is an updated solution for Bootstrap 3 (should work for older versions though) that uses CSS/LESS only:

http://jsfiddle.net/silb3r/0srp42pb/11/

You set the font-size to 0 on the row (otherwise you'll end up with a pesky space between columns), then remove the column floats, set display to inline-block, re-set their font-size, and then vertical-align can be set to anything you need.

No jQuery required.

cfx
  • 3,311
  • 2
  • 35
  • 45
  • I want to keep it at middle. However in your jsfiddle when i tried "vertical-allign:middle" then it didn't work. Any thoughts? – joy Mar 08 '15 at 03:31
  • Try setting both `div`s to `vertical-align: middle;`. – cfx Mar 08 '15 at 03:37
  • 6
    This is the only acceptable answer! @Lukas's will ignore widths on columns that don't fill a row. And DOM manipulation for styling... SMH. – Archonic May 30 '15 at 03:59
  • Your CSS is keyed off the row (specifically, `.myrow`)...doesn't this mean you can't have one column top-aligned, one column bottom-aligned, and a third column top-aligned? – Jeromy French Jun 02 '15 at 14:37
  • Thanks ! Works fine with Bootstrap 4. – Elie Teyssedou Jan 27 '16 at 09:14
  • You can replace 'last-child' by 'first-child' if you want to have the first element at the bottom and the last at the top. – Elie Teyssedou Jan 27 '16 at 09:24
  • This I think is the best answer and even preferable to using flexbox, since that can easily not work with fluid layours with standard BS 3 at lower resolutions. – rmcsharry Sep 05 '16 at 22:31
  • Finally a pure design solution for bootstrap structure. Thanks ! – George Dimitriadis Jan 24 '17 at 13:38
  • Does not work if you want to have one of the columns `vertical-align:middle` and another on top or bottom. – MarcGuay Jul 24 '17 at 19:19
49

Please note: for Bootstrap 4+ users, please consider Christophe's solution (Bootstrap 4 introduced flexbox, which provides for a more elegant CSS-only solution). The following will work for earlier versions of Bootstrap...


See http://jsfiddle.net/jhfrench/bAHfj/ for a working solution.

//for each element that is classed as 'pull-down', set its margin-top to the difference between its own height and the height of its parent
$('.pull-down').each(function() {
  var $this = $(this);
  $this.css('margin-top', $this.parent().height() - $this.height())
});

On the plus side:

  • in the spirit of Bootstrap's existing helper classes, I named the class pull-down.
  • only the element that is getting "pulled down" needs to be classed, so...
  • ...it's reusable for different element types (div, span, section, p, etc)
  • it's fairly-well supported (all the major browsers support margin-top)

Now the bad news:

  • it requires jQuery
  • it's not, as-written, responsive (sorry)
Jeromy French
  • 11,812
  • 19
  • 76
  • 129
  • 3
    for responsiveness, perhaps hook the window.resize? http://stackoverflow.com/a/2969091/244811 – Scott Weaver Jan 15 '13 at 04:46
  • 25
    Don't use a jQuery solution for something that could be a CSS solution. There's many reasons to avoid DOM manipulation for styling purposes. – Archonic May 30 '15 at 03:43
  • 1
    @Archonic : what is that CSS-only solution? I would also prefer it to a JS-dependent solution. Just keep in mind OP's stipulation: "a solution where I didn't have to specify the absolute height of my divs would be preferred" – Jeromy French Jun 01 '15 at 13:23
  • 1
    @cfx Posted a css only solution with a fiddle that doesn't require absolute heights. – Archonic Jun 02 '15 at 03:37
  • 1
    On the other hand, my solution allows the user to bottom-align individual elements (giving similar behaviour to Bootstrap's `.pull-left` and `.pull-right`), without affecting siblings. Can that be done with CSS-only solution? – Jeromy French Jun 02 '15 at 14:38
  • 1
    Thanks for this solution. Changed "margin-top" to "padding-top" to make this work for sticky footer etc. – Sverrir Sigmundarson Apr 06 '16 at 20:49
36

You can use flex:

@media (min-width: 768px) {
  .row-fluid {
    display: flex;
    align-items: flex-end;
  }
}
Christophe
  • 958
  • 12
  • 20
  • Using felx is very nice and straightforward in my opinion and I had one more advantage using "align-items: baseline" that was great with differet fonts in the different items to align. – Alessandro Dentella Mar 12 '16 at 17:05
  • Excellent suggestion to use flex. Simple, strait-forward, and uses Bootstrap to solve a Bootstrap problem. – CheddarMonkey Sep 06 '17 at 21:31
  • 1
    Brilliant answer and works perfectly with bootstrap with no javascript / jquery needed. – Filth Nov 08 '17 at 12:37
  • 1
    Yup, add this to a regular bootstrap row and bam, it works. Beautiful. How a non-responsive, jquery solution became the top answer? We'll never know. – Levi Fuller Dec 14 '17 at 18:51
  • @LeviFuller My guess is because this solution only supports one breakpoint – clamchoda Jul 16 '19 at 21:07
  • In addition to using d-flex I added align-items-end to my col and my button aligned to the bottom in the grid. Was useful because I had 2 other columns with labels. Prior the button was at the top and did not align properly with the input boxes. – Robert Saylor Feb 17 '21 at 12:31
27

You need to add some style for span6, smthg like that:

.row-fluid .span6 {
  display: table-cell;
  vertical-align: bottom;
  float: none;
}

and this is your fiddle: http://jsfiddle.net/sgB3T/

Lukas
  • 7,384
  • 20
  • 72
  • 127
  • 4
    I would create a specific css class instead of setting it to span6, but the table-cell strategy works well! I also had to set "display: table-row" to the containing div to have correct widths. – Meta-Knight Jan 09 '14 at 15:30
  • 3
    For Bootstrap 3 I added this rule: .row.align-bottom > [class^=col]{ display: table-cell; vertical-align: bottom; float: none; } apply align-bottom to the row <div class="row align-bottom"> – Martin Aug 22 '14 at 12:20
  • @Martin, your rule works fine when you also set .align-bottom { display: table-row;}, however, the row alignment is off because table rows don't respect the bootstrap margin-left and margin-right: -15px......thoughts? – Alex White Oct 28 '14 at 19:23
  • @AlexWhite - Put `padding-left: 0` and `padding-right: 0` on all the cols in that row. – AnalogWeapon Jan 27 '15 at 20:42
  • 1
    This will ignore column widths when columns don't fill the width of a row. When using offsets for example. – Archonic May 30 '15 at 04:00
14

Here's also an angularjs directive to implement this functionality

    pullDown: function() {
      return {
        restrict: 'A',
        link: function ($scope, iElement, iAttrs) {
          var $parent = iElement.parent();
          var $parentHeight = $parent.height();
          var height = iElement.height();

          iElement.css('margin-top', $parentHeight - height);
        }
      };
    }
Ilya Schukin
  • 303
  • 7
  • 11
7

Just set the parent to display:flex; and the child to margin-top:auto. This will place the child content at the bottom of the parent element, assuming the parent element has a height greater than the child element.

There is no need to try and calculate a value for margin-top when you have a height on your parent element or another element greater than your child element of interest within your parent element.

zdebruine
  • 3,687
  • 6
  • 31
  • 50
  • This should be the accepted answer: it's short, simple, and works in any browser that supports flex. The only drawback is it breaks responsiveness. – tbm Aug 07 '17 at 14:27
5

This is based on cfx's solution, but rather than setting the font size to zero in the parent container to remove the inter-column spaces added because of the display: inline-block and having to reset them, I simply added

.row.row-align-bottom > div {
    float: none;
    display: inline-block;
    vertical-align: bottom;
    margin-right: -0.25em;
}

to the column divs to compensate.

Kirtlander
  • 91
  • 1
  • 4
4

Based on the other answers here is an even more responsive version. I made changes from Ivan's version to support viewports <768px wide and to better support slow window resizes.

!function ($) { //ensure $ always references jQuery
    $(function () { //when dom has finished loading
        //make top text appear aligned to bottom: http://stackoverflow.com/questions/13841387/how-do-i-bottom-align-grid-elements-in-bootstrap-fluid-layout
        function fixHeader() {
            //for each element that is classed as 'pull-down'
            //reset margin-top for all pull down items
            $('.pull-down').each(function () {
                $(this).css('margin-top', 0);
            });

            //set its margin-top to the difference between its own height and the height of its parent
            $('.pull-down').each(function () {
                if ($(window).innerWidth() >= 768) {
                    $(this).css('margin-top', $(this).parent().height() - $(this).height());
                }
            });
        }

        $(window).resize(function () {
            fixHeader();
        });

        fixHeader();
    });
}(window.jQuery);
bbodenmiller
  • 3,101
  • 5
  • 34
  • 50
0

Well, I didn't like any of those answers, my solution of the same problem was to add this:<div>&nbsp;</div>. So in your scheme it would look like this (more or less), no style changes were necessary in my case:

-row-fluid-------------------------------------
+-span6----------+ +----span6----------+
|                | | +---div---+       |
| content        | | | & nbsp; |       |
| that           | | +---------+       |
| is tall        | | +-----div--------+|   
|                | | |short content   ||
|                | | +----------------+|
+----------------+ +-------------------+
-----------------------------------------------
jan b
  • 67
  • 1
  • 5
-3
.align-bottom {
    position: absolute;
    bottom: 10px;
    right: 10px;
}