5

I have multiple items organized in multiple columns and rows

 <div class="items">
    <div class="item-1">
    <div class="item-2">
    <div class="item-3">
    <div class="item-4">
    <div class="item-5">
    ...
 </div>

I'm using jQuery slidedown to show hide content of each item when clicks. I want to push the bottom content correctly, ie extend the same column to which the object belongs.

Example with basic float:left and width:33%

http://jsfiddle.net/kurtko/4w8n1frr/

I have tried several methods:

1) Using columns with float:left, then insert items changing the order with PHP. From: 1,2,3,4,5,6,7,8,9 to 1,4,7,2,5,8,3,6,9.

http://jsfiddle.net/kurtko/adLL8gmn/

<div class="items">    
 <div class="column>
   <div class="item-1">
   <div class="item-4">
   <div class="item-7">
 </div>
 <div class="column>
   <div class="item-2">
   <div class="item-5">
   <div class="item-8">
 </div>
</div>

This is a good method, but when I use responsive version with one column the order is incorrect.

2) Masonry. Masonry - Isotope has a custom layout mode called 'masonryColumnShift' but in current version 2 is disabled.

http://isotope.metafizzy.co/v1/custom-layout-modes/masonry-column-shift.html

3) Flexbox. Using:

http://jsfiddle.net/kurtko/7cu5jvrr/

.items {    
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    align-items: flex-start;
}

.item {
   width: 33.3%;
}

Good results but not perfect. When an item changes its height a white space is created below the row.

Any ideas?

Thanks.

kurtko
  • 1,306
  • 3
  • 18
  • 41

2 Answers2

1

Update (4/21/15)

This is a pretty major update on what I had before. I'm using jQuery to find all the div's, and sort them into a .new div. When the screen becomes smaller than 600px, I put them back into their original configuration, and stack them in order to be viewed better on a mobile device.

You can see it live here.

$(document).ready(function() {
  var divsAccross = 3;       // DIV's accross
  var elmParent = '.items';  // Container Class
  var elmChild = '.item';    // Elements to be sorted
  var createdDiv = 'new';    // New DIV created to hold the new sort
  var sortBy = 'id';         // Sort Elements by...

  // Shouldn't have to edit anything below.
  var windowSize = $(window).width();
  var totalDivs = [];
  var scrnSize = "large";
  var newWidths = Math.floor(100 / divsAccross);
  var newMargin = (100 % divsAccross) / (divsAccross - 1);

  $(elmChild).each(function() {
    totalDivs.push($(this).attr(sortBy));
  });

  var matrix = listToMatrix(totalDivs, divsAccross);

  if (windowSize > 600) {
    reOrder(matrix);
    scrnSize = "large";
  } else {
    scrnSize = "small";
  }

  $(elmChild).click(function() {
    $(this).find('.hidden').slideToggle(500);
  });

  $(window).resize(function() {
    windowSize = $(window).width();

    if (windowSize <= 600) {
      if (scrnSize == "large") {
        var $mylist = $(elmParent);

        $mylist.find(elmChild).sort(function(a, b) {
          return +a.getAttribute(sortBy) - +b.getAttribute(sortBy);
        }).appendTo($mylist);
        $("." + createdDiv).remove();
        scrnSize = "small";
      }
    } else {
      if (scrnSize == "small") {
        reOrder(matrix);
        scrnSize = "large";
      }
    }
  });

  function reOrder(list) {
    for (var d = 0; d < list.length; d++) {
      for (var n = 0; n < list[d].length; n++) {
        $('#' + list[d][n]).addClass(' ' + d);
      }
      $('.' + d).wrapAll("<div class=" + createdDiv + "></div>");
      $('.' + createdDiv).css({
        'width': newWidths + '%',
        'margin': '0 ' + newMargin + '% 0 0'
      })
    }
  }

  function listToMatrix(list, elementsPerSubArray) {
    var matrix = [],
      i, k;
    var newMatrix = [],
      x, y;

    for (i = 0, k = -1; i < list.length; i++) {
      if (i % elementsPerSubArray === 0) {
        k++;
        matrix[k] = [];
      }
      matrix[k].push(list[i]);
    }

    for (x = 0; x < elementsPerSubArray; x++) {
      newMatrix[x] = [];
      for (y = 0; y < matrix.length; y++) {
        if (matrix[y][x] != null) {
          newMatrix[x].push(matrix[y][x]);
        }
      }
    }
    return newMatrix;
  }
});
* {
  margin: 0;
  padding: 0;
}
.items {
  margin: 0.5%;
  height: 100%;
}
.item {
  padding: 20px 0;
  margin: 0 5px 5px 0;
  background: darkgreen;
  text-align: center;
  width: 100%;
  border: 1px solid red;
  cursor: pointer;
  float: left;
}
.new {
  float: left;
}
.new:last-child {
  margin: 0 !important;
}
.hidden {
  display: none;
  margin-top: 20px;
  width: 100%;
  padding: 150px 0;
  border-top: 1px solid red;
  border-bottom: 1px solid red;
  background-color: orange;
}
@media all and (max-width: 600px) {
  .items {
    display: flex;
    flex-flow: row wrap;
    height: 100%;
  }
  .items > * {
    flex: 1 100%;
    width: 100%;
    float: none;
  }
  .two {
    order: 2;
  }
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="items">
  <div class="item" id="1">1
    <div class="hidden">Hide</div>
  </div>
  <div class="item" id="2">2
    <div class="hidden">Hide</div>
  </div>
  <div class="item" id="3">3
    <div class="hidden">Hide</div>
  </div>
  <div class="item" id="4">4
    <div class="hidden">Hide</div>
  </div>
  <div class="item" id="5">5
    <div class="hidden">Hide</div>
  </div>
  <div class="item" id="6">6
    <div class="hidden">Hide</div>
  </div>
  <div class="item" id="7">7
    <div class="hidden">Hide</div>
  </div>
  <div class="item" id="8">8
    <div class="hidden">Hide</div>
  </div>
  <div class="item" id="9">9
    <div class="hidden">Hide</div>
  </div>
  <div class="item" id="10">10
    <div class="hidden">Hide</div>
  </div>
  <div class="item" id="11">11
    <div class="hidden">Hide</div>
  </div>
</div>

Update (4/22/15)

Updated the function in case you plan to have more than nine div's and to put all the controls of everything at the top. You shouldn't need to edit anything beyond the first five variable. The only thing you could do further would be to turn this into a plugin of it's own.

FiSH GRAPHICS
  • 1,051
  • 2
  • 13
  • 25
0

Based on your option 1.

Replace the float: left with display: inline-block; The advantage is that the items don't float and will stay in the same line as the other items. When expanding, the line-height will do to, making the next row complete pushed down.

Will also work responsively.

You'll also need to set the vertical alignment to top.

Updated Fiddle

LinkinTED
  • 16,671
  • 4
  • 27
  • 53
  • But white space is created below the row as with the option of FlexBox. Items that are not pushed should not move from its original place – kurtko Apr 20 '15 at 12:17
  • 1
    Ah, okay, I didn't get that out of your question. Then my answer is false. But I'll leave it anyways, it might be at use for someone else. – LinkinTED Apr 20 '15 at 13:46