Search code examples
javascriptjqueryhtmltwitter-bootstrapmasonry

Bootstrap collapsing panels overlap each other when I use Masonry


I have the next page:

    $(function () {
        var container = document.querySelector('#PanelContainer');
        var msnry = new Masonry(container, {
            itemSelector: '.selector-class',
            isAnimated: true,
            animationOptions: {
                duration: 750,
                easing: 'linear',
                queue: false
            }   
        });
        $(".spoiler-trigger").click(function () {
            $(this).parent().next().collapse('toggle');
        });
    })
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.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>

<script src="https://unpkg.com/masonry-layout@4/dist/masonry.pkgd.min.js"></script>

<div class="container">
<div id="PanelContainer" class="row">
    <div class="col-md-6 selector-class">
        <div class="panel panel-primary card-0">
          <div class="panel-heading">
            <h3 class="panel-title">Title</h3>
        </div>
        <div class="panel-body">
          <div class="panel panel-default">
            <div class="panel-heading">
              <button type="button" class="btn btn-default btn-xs spoiler-trigger" data-toggle="collapse">Collapse</button>
            </div>
            <div class="panel-collapse collapse out">
              <div class="panel-body">Body</div>
            </div>
          </div>
        </div>
      </div>
    </div>
    <div class="col-md-6 selector-class">
        <div class="panel panel-primary card-0">
          <div class="panel-heading">
            <h3 class="panel-title">Title</h3>
        </div>
        <div class="panel-body">
          <div class="panel panel-default">
            <div class="panel-heading">
              <button type="button" class="btn btn-default btn-xs spoiler-trigger" data-toggle="collapse">Collapse</button>
            </div>
            <div class="panel-collapse collapse out">
              <div class="panel-body">Body</div>
            </div>
          </div>
        </div>
      </div>
    </div>
    <div class="col-md-6 selector-class">
        <div class="panel panel-primary card-0">
          <div class="panel-heading">
            <h3 class="panel-title">Title</h3>
        </div>
        <div class="panel-body">
          <div class="panel panel-default">
            <div class="panel-heading">
              <button type="button" class="btn btn-default btn-xs spoiler-trigger" data-toggle="collapse">Collapse</button>
            </div>
            <div class="panel-collapse collapse out">
              <div class="panel-body">Body</div>
            </div>
          </div>
        </div>
      </div>
    </div>
    <div class="col-md-6 selector-class">
        <div class="panel panel-primary card-0">
          <div class="panel-heading">
            <h3 class="panel-title">Title</h3>
        </div>
        <div class="panel-body">
          <div class="panel panel-default">
            <div class="panel-heading">
              <button type="button" class="btn btn-default btn-xs spoiler-trigger" data-toggle="collapse">Collapse</button>
            </div>
            <div class="panel-collapse collapse out">
              <div class="panel-body">Body</div>
            </div>
          </div>
        </div>
      </div>
    </div>
</div>
</div>

All looks perfect but when the user tries to expand any panels that overlaps others. How can I make to Masonry recalculates and smooth updates panels' locatons?
P.S. I am a noobie in JS.

ADDED
I set listeners for Bootstrap events:

$(document).on('hidden.bs.collapse', function () {
    msnry.layout();
});
$(document).on('shown.bs.collapse', function () {
    msnry.layout();
});

And my layout began to update self but if it has a wrong behavior for expanding. Now, the panel expanded and after it calls layout updating but I need to make it before.


Solution

  • Hopefully this can help, i got this working, but only when using col-XX-[3/6/12] (due to the requirement on width: being a nice %age)

    It's a tad messy, but functional.

    things worth changing/noting:

    to get around the layout change on collapse/expand, the JS has a setTimeout that runs on the update; in production, or especially for slower animated expand/collapse sequences, i imagine a better solution would need to be found. but for animations less than 100ms, i reckon you'd get away with this.

    On the CSS, if you used any bootstrap column bigger than xs, you'd need to adapt the css grid-item[-6,-12] to match the col rules for changing width % with screen size.

    Mostly the bootstrap column rules take precedence, so things dont get too wrecked.

    [NB: my .click event is bound to the text header on the panel, not the panel header div]

    $('.grid').masonry({
      itemSelector: '.grid-item',
      columnWidth: '.grid-sizer',
      percentPosition: true,
    
    });
    
    $('.panel-heading').click(function () {
    	setTimeout(function() {
    		$('.grid').masonry('layout');
    	}, 300);
    });
    .grid-sizer, .grid-item {width: 25%;}
    
    .grid-item--width-6 { width: 50%;}
    
    .grid-item--width-12 { width: 100%;}
    
    /* NOT required to work,it 
    helps demo whats going on */
    .panel-body {
    	height: 200px;
    }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.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>
    
    <script src="https://unpkg.com/masonry-layout@4/dist/masonry.pkgd.min.js"></script>
    
    <link href="css/main.css" rel="stylesheet">
    
    
    
    <div class="grid">
      <div class="grid-sizer"></div>
    
      <div class=" col-xs-12 grid-item grid-item--width-12">
        <div class="panel panel-default">
          <div class="panel-heading">
            <h4 class="panel-title">
              <a data-toggle="collapse" href="#collapse0-m">panel 0</a>
            </h4>
          </div>
          <div id="collapse0-m" class="panel-collapse collapse">
            <div class="panel-body">Panel Body</div>
          </div>
        </div>
      </div>
    
    
      <div class=" col-xs-6 grid-item grid-item--width-6">
        <div class="panel panel-default">
          <div class="panel-heading">
            <h4 class="panel-title">
              <a data-toggle="collapse" href="#collapse1-m">panel 1</a>
            </h4>
          </div>
          <div id="collapse1-m" class="panel-collapse collapse">
            <div class="panel-body">Panel Body</div>
          </div>
        </div>
      </div>
    
      <div class="col-xs-6 grid-item grid-item--width-6">
        <div class="panel panel-default">
         <div class="panel-heading">
           <h4 class="panel-title">
             <a data-toggle="collapse" href="#collapse2-m">panel 2</a>
           </h4>
         </div>
         <div id="collapse2-m" class="panel-collapse collapse">
           <div class="panel-body">Panel Body</div>
         </div>
       </div>
      </div>
    
      <div class="col-xs-3 grid-item">
        <div class="panel panel-default">
          <div class="panel-heading">
            <h4 class="panel-title">
              <a data-toggle="collapse" href="#collapse3-m">panel 3</a>
            </h4>
          </div>
          <div id="collapse3-m" class="panel-collapse collapse">
            <div class="panel-body">Panel Body</div>
          </div>
        </div>
      </div>
    
      <div class="col-xs-3 grid-item">
        <div class="panel panel-default">
          <div class="panel-heading">
            <h4 class="panel-title">
              <a data-toggle="collapse" href="#collapse4-m">panel 4</a>
            </h4>
          </div>
          <div id="collapse4-m" class="panel-collapse collapse">
            <div class="panel-body">Panel Body</div>
          </div>
        </div>
      </div>
    
      <div class="col-xs-6 grid-item grid-item--width-6">
        <div class="panel panel-default">
          <div class="panel-heading">
            <h4 class="panel-title">
              <a data-toggle="collapse" href="#collapse5-m">panel 5</a>
            </h4>
          </div>
          <div id="collapse5-m" class="panel-collapse collapse">
            <div class="panel-body">Panel Body</div>
          </div>
        </div>
      </div>
    
    </div>
    
    
    
        <!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
    
        <script src="js/main.js"></script>
    
        <!-- Include all compiled plugins (below), or include individual files as needed -->