Bootstrap: Docs aren't clear about whether .card-columns orders cards vertically or horizontally

Created on 9 Mar 2016  路  16Comments  路  Source: twbs/bootstrap

The card-columns component is sorting cards vertically rather than horizontally. If you have 6 cards, from 0 to 5 you'll see something like:

0 2 4
1 3 5

But you should see something like:

0 1 2
3 4 5

docs v4

Most helpful comment

But is any one knows how can I change the sorting to :
0 1 2
3 4 5
?

All 16 comments

The documentation example (http://v4-alpha.getbootstrap.com/components/card/#columns ) uses

0 2 4
1 3 5

-style ordering, so I assume this is working as intended. However, the documentation doesn't explicitly state the expected ordering, so I'll leave this open as a docs bug.

But is any one knows how can I change the sorting to :
0 1 2
3 4 5
?

I think it isn't useful a columns system that doesn't sort the cards the same way we read (from left to right, from top to bottom... in that order). I agree that if this is the functionality expected, it should be specified in the docs. But I don't think most people will find this useful.

It less docs bug and more functionality issue (my question), so is any one can help me regarding transposing (?) the table cells? Should I do it manually via MutationObserver ?any one has a better suggestion?
thanks!

I ended up using the grid system. It's not ideal, but it's more customizable and more responsive-

CC: @mdo

The columns you're seeing are implemented with CSS's column properties. As far as I know, there is no way to change them. They flow from top to bottom, left to right as those properties are meant to be used for bodies of text I believe.

Addressed in #19459 and a follow up commit, 5aa32b3.

Hi all! Thanks for the clarification, @mdo. Does anyone found an alternative solution? @igorgordonsu

@lucaszmoraes yeah, it is not the prettiest solution but doing something like:

<div class="row">
  <div class="col-lg-6">
    <div class="card">card[0]</div>
    <div class="card">card[2]</div>
    <div class="card">card[4]</div>
  </div>
  <div class="col-lg-6">
    <div class="card">card[1]</div>
    <div class="card">card[3]</div>
    <div class="card">card[5]</div>
  </div>
</div>

Notice the even indexes on the first column, and the odd ones on the second.
That worked for me, you will have to use the responsive utility classes to build a layout with only one column for small devices, or your cards will lose their order.

@svinci but this takes away the masonry look.

For anyone still interested, I put together a little work-around for those who are building their cards dynamically and can't hardcode it, but still want sorting with left to right THEN top to bottom display. It should work no matter how many cards you have, but may break if your cards are of vastly differing sizes.

In essence what you do is sort your data by whatever criteria you want so you have [0, 1, 2, 3, 4, 5, 6, 7, 8, ...]. Then, from that create a 2D array (aka matrix) where each row is of length 3, i.e. [ [0, 1, 2], [3, 4, 5] , [6, 7, 8], ...]. Then read that matrix vertically into a final array so that it looks like [0, 3, 6, 1, 4, 7, 2, 5, 8, ...], and build your cards from that final array. There's some special handling necessary if the last two rows would each have 2 cards. Code sample below.

  sorted = data.sort(function (a, b) { return a.sortCriterion > b.sortCriterion; });
  dataIn3s = [];
  lastTwoRows = [];
  for (i = 0; i < sorted.length; i += 3) {
    row = [];
    if (i + 4 == sorted.length) {
      lastTwoRows = [[sorted[i], sorted[i+1]], [sorted[i+2], sorted[i+3]]];
      break;
    }
    else {
      row.push(sorted[i]);
      if ((i+1) < sorted.length) {
        row.push(sorted[i+1]);
      }
      if ((i+2) < sorted.length) {
        row.push(sorted[i+2]);
      }
    }
    dataIn3s.push(row);
  }
  if (lastTwoRows.length == 2) {
    dataIn3s.push(lastTwoRows[0]);
    dataIn3s.push(lastTwoRows[1]);
  }

  jankedData = [];
  for (i = 0; i < dataIn3s.length; i++) {
    jankedData.push(dataIn3s[i][0]);
  }
  for (i = 0; i < dataIn3s.length; i++) {
    if (dataIn3s[i].length > 1) {
      jankedData.push(dataIn3s[i][1]);
    }
  }
  for (i = 0; i < dataIn3s.length; i++) {
    if (dataIn3s[i].length == 3) {
      jankedData.push(dataIn3s[i][2]);
    }
  }

  for (i = 0; i < jankedData.length; i++) {
      card = buildCardFromData(jankedData[i]);
      $("#cardContainer").append(card);
  }

@benNThompson your code kinda work, after "2 rows" i only get 2 column each "row"

Hey @mattiasghodsian. Unfortunately, that's not an issue with my code; that's the default behavior for bootstrap's card-columns class. It builds the columns top to bottom THEN left to right, so if you have (3*n)+4 cards (where n is a non-negative integer) it will put the last 4 cards into two rows of two columns each, resulting in the behavior you're seeing. For proof, try removing my bit of code and then using the card-columns class with 4, 7, 10, or 13 cards. You will see that in all those cases, the last four cards are in two rows of two columns.

The only way to properly fix this issue would be to rewrite the card-columns class. Which seems to have been the reason @svinci opened this issue in the first place. Judging by the fact that @mdo updated the docs and closed this issue, that seems unlikely to happen.

As a workaround, you could try taking the lastTwoRows array from my code sample, and instead of adding it to the dataIn3s array, use it to manually build a grid that looks the way you want, and insert it after the card container

I also faced a similar problem with bootstrap.
I was getting my cards arranged as below -
0 4 8
1 5 9
2 6 10
3 7 11
Required was -
0 1 2
3 4 5
6 7 8
9 10 11

So I used the first value of each loop as 0, 1, 2 then ran their respective three loops until the length of array and pushed the 3rd value into another array.
input array - [0,1,2,3,4,5,6,7,8,9,10,11]
output array - [0,3,6,9,1,4,7,10,2,5,8,11]

Below is the code that was used -
var i = 0; while(i<docs.length) { resultant.push(docs[i]); i = i + 3; }
var i = 1; while(i<docs.length) { resultant.push(docs[i]); i = i + 3; }
var i = 2; while(i<docs.length) { resultant.push(docs[i]); i = i + 3; }
return resultant;

Hello, not sure if im too late to the party but use row and col combination while leaving out colums class and include your cards within cols "grid markup", like so:

<div class="row">
    <div class="col-sm-4">
      <div class="card">Lorem ipsum...</div >
    </div>
    // extra card as an example, this works with dynamic info aswell
    <div class="col-sm-4">
      <div class="card">Sed ut perspiciatis...</div >
    </div>
  </div>

"col-sm-4" class does the trick for me to filter the layout of 3 in a horizontal deck
p.s. just be sure to wrap each card with col and apart from the horizontal layout being static (the crads height might change thus leading to having bigger gaps between upper and lower horizontal deck) this method works perfectly. Other then that if you intend to use cards for huge amount of information and the crads change sizes dramatically, then you should use some other plugin or try the above approaches. For my purpose I use text-truncate class for text layout thus sparing me from the horror of "wee but I want it that way... :("

Was this page helpful?
0 / 5 - 0 ratings