Gap in Bootstrap stacked rows
Asked Answered
O

3

10

I am building a Bootstrap 3 grid that will become a portfolio page eventually. In the following bootply, in the first example, you can see it works perfectly stacking from 6 to 4 to 3 in my bootply

However in the second example, on the same bootply, there is an item where the tile for the item is longer and it causes a gap in the grid when it stacks.

What is the best bootstrap friendly ,solution to this? Any help much appreciated.

Orlantha answered 4/7, 2014 at 9:30 Comment(0)
U
17

There are a couple of ways to handle this:

  1. Give all of the elements in your portfolio a set height.
  2. Use something like masonry to dynamically "fit" the elements into the available space.
  3. Use the responsive classes and clearfix as described in the doc under the heading Responsive column resets, in the Grid secion.
  4. Use jQuery to adjust the column heights dynamically.

If your content is dynamically generated so that you don't know which elements will have longer content, and you have different layouts set for different breakpoints, the responsive classes approach can be a bear to adapt. I use a little trick. After each element in the grid, I add a div that I can apply a mini clearfix to using media queries. It's extra markup, but it solves the problem nicely and allows me to have readable and maintainable markup while avoiding the use of javascript to adjust the layout. Here's an example using your markup:

Updated Bootply

<div class="row portfolio"> <!--Add a class so you can target with nth-child-->
    <div class="col-lg-2 col-sm-3 col-xs-4">
        <div class="panel panel-default">
            <div class="panel-body">
                <a href="#">
                    <img src="http://placehold.it/200x200" class="img-thumbnail img-responsive">
                </a>
            </div>
            <div class="panel-footer">
                This is text
            </div>  
        </div> 
    </div>
    <div class="clear"></div> <!--Here's the added div after every element-->
  ....
</div> <!--/.portfolio.row-->

CSS:

@media (max-width: 767px) {
    .portfolio>.clear:nth-child(6n)::before {
      content: '';
      display: table;
      clear: both;
    }
}
@media (min-width: 768px) and (max-width: 1199px) {
    .portfolio>.clear:nth-child(8n)::before {
      content: '';
      display: table;
      clear: both;
    }
}
@media (min-width: 1200px) {
    .portfolio>.clear:nth-child(12n)::before {  
      content: '';
      display: table;
      clear: both;
    }
}

If you prefer the jQuery route (again, this assumes that you've added a class "portfolio" to the row that contains your portfolio elements for easier targeting):

var row=$('.portfolio');
$.each(row, function() {
    var maxh=0;
    $.each($(this).find('div[class^="col-"]'), function() {
        if($(this).height() > maxh)
            maxh=$(this).height();
    });
    $.each($(this).find('div[class^="col-"]'), function() {
        $(this).height(maxh);
    });
});
Unscratched answered 4/7, 2014 at 9:59 Comment(3)
Yes it's dynamic content, I don't know how I missed that section in the bootstrap docs, thanks for the link, as it happens the java script method is working well and on balance I think I'll stick with that. Thanks.Orlantha
Cool... depending on my situation I'll do that as well. A note of warning though: remember to handle the resize event because you're setting the height to a fixed height (so if the user resizes the page, stuff can get cut off or have giant gaps). That's one of the reasons why I came up with the css approach.Unscratched
This is an excellent solution and I've successfully implemented it in my project. One suggestion though - add a note to modify the :nth-child selector based on the number of desired columns per row.Kalmia
P
7

A Bootstrap "only" approach is to use Bootstrap's .clearfix. You have to iterate this every x number of columns, so in your case a clearfix div would be placed after the 6th col-lg-2. This will work for lg screen widths..

http://www.bootply.com/SV0kI3TSN3

However since you're using multiple responsive breakpoints, you'd need to place a clearfix where the md and xs colums wrap too. This will prevent the gap at all screen widths.

http://www.bootply.com/3TsF0arPRS

Update 2017

1 - As explained above, the 'clearfix' approach (recommended by Bootstrap) like this (requires iteration every x columns). This will force a wrap every 3 columns

<div class="row">
    <div class="col-md-4">Content</div>
    <div class="col-md-4">Content</div>
    <div class="col-md-4">Content</div>
    <div class="clearfix"></div>
    <div class="col-md-4">Content</div>
    <div class="col-md-4">Content</div>
    <div class="col-md-4">Content</div>
    <div class="clearfix"></div>
    <div class="col-md-4">Content</div>
    <div class="col-md-4">Content</div>
    <div class="col-md-4">Content</div>
</div>

Clearfix Demo (single tier)

Clearfix Demo (responsive tiers)

There is also a CSS-only variation of the 'clearfix' (unsupported). http://www.codeply.com/go/lUbs1JgXUd

2 - Make the columns the same height (using flexbox):

Since the issue is caused by the difference in height, you can make columns equal height across each row. Flexbox is the best way to do this, and is natively supported in Bootstrap 4.

.row.display-flex {
  display: flex;
  flex-wrap: wrap;
}
.row.display-flex > [class*='col-'] {
  display: flex;
  flex-direction: column;
}

Flexbox equal height Demo

3 - CSS3 columns approach (Masonry-like CSS solution)..

This is not native to Bootstrap 3, but another approach using CSS multi-columns. One downside to this approach is the column order is top-to-bottom instead of left-to-right.

CSS3 columns Demo

4 - JavaScript/jQuery approach

Finally, you may want to use a plugin such as Isotope/Masonry:

Bootstrap Masonry Demo


More on Bootstrap Variable Height Columns

Preposterous answered 4/7, 2014 at 10:17 Comment(2)
due to the fact that i always show 3 columns for every screen width, adding a clearfix-div after every third column works fine for me, thanks! :)Broadsword
solution 2 "flex-wrap" worked brilliantly even though I was using container-fluid and had different heights items! Thx, you made my day.Thrall
S
0

I had the same problem with two panels side-by-side in a row.

I did not find any CSS hack for this, so I gave the two panels a same-height class and I use this JS code.

boxes = $(".same-height");
maxHeight = Math.max.apply(Math, boxes.map(function () {
    return $(this).height()
}).get());
boxes.height(maxHeight);

Here is a BootPly link that use the code above: http://www.bootply.com/622XyQ0oH5

Of course, you have to adapt your CSS rules I you want to avoid blank spaces.

Sliver answered 4/7, 2014 at 9:44 Comment(2)
Works great, I put the class same-height on the columns div and this removed the whitespace in your bootply: bootply.com/7MxWONVomUOrlantha
Some further testing, and adding this to the wordpress theme where and I had some strange issues with the columns setting themselves to 50px high and overlapping if the page was refreshed. As suggestion number 1 from @Unscratched sounded too simple to be true I thought I would give that a go and it actually worked very well and I'm sure will be the most easy to understand and maintain. I thought the fixed size would leave big gaps at smaller sizes but as it happens for typical post titles it works really well, the smaller the images the more lines of text underneath filling the fixed size.Orlantha

© 2022 - 2024 — McMap. All rights reserved.