Search code examples
jquerycssjquery-masonrymasonrypackery

Packery / Masonry not honoring stamp items when grid is rotated


When using Packery, if I rotate the grid by 45 degrees, the stamped items no longer affect the layout. Why is this happening?

Normally, Packery will layout items around stamped elements. My project is using Packery, but while investigating I discovered that this same issue also occurs in masonry.

I'm rotating the grid using css:

.grid {
  transform:rotate(-45deg);
}

You can see an example of the issue on this codepen. As the documentation explains, Packery should lay out item elements around stamped elements (explained here and here).

Any ideas for workarounds would also be helpful.

(Bounty says 90 degrees. It should say 45 degrees (plus or minus)).


Solution

  • It seems like the implicit call to .layout() during initialization incorrectly renders rotated stamped objects when the rotation is defined in CSS.

    Here is a work-around:

    1. Remove your rotation CSS rules from .grid
    2. Add the following code after initialization of the grid:

      $('.grid').css({
        '-webkit-transform': 'rotate(-45deg)',
        'transform': 'rotate(-45deg)'
      });
      

    Updated CodePen

    // external js: packery.pkgd.js
    
    $('.grid').packery({
      itemSelector: '.grid-item',
      stamp: '.stamp'
    });
    
    $('.grid').css({
      '-webkit-transform': 'rotate(-45deg)',
      'transform': 'rotate(-45deg)'
    });
    * { box-sizing: border-box; }
    
    body { font-family: sans-serif; }
    
    /*--- grid ---*/
    
    .grid {
      background: #DDD;
      max-width: 1200px;
      position: relative;
    }
    
    /* clear fix */
    .grid:after {
      content: '';
      display: block;
      clear: both;
    }
    
    /* ---- .grid-item ---- */
    
    .grid-item {
      float: left;
      width: 100px;
      height: 100px;
      background: #C09;
      border: 2px solid hsla(0, 0%, 0%, 0.5);
    }
    
    .grid-item--width2 { width: 200px; }
    .grid-item--height2 { height: 200px; }
    
    .stamp {
      position: absolute;
      width: 30%;
      height: 120px;
      background: #C90;
      border: 4px dotted hsla(0, 0%, 0%, 0.5);
    }
    
    .stamp1 {
      left: 20%;
      top: 0px;
    }
    
    .stamp2 {
      right: 10%;
      top: 110px;
    }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <script src="http://mfzy.co/packery.pkgd.js"></script>
    
    <h3>Packery - stamp option with rotated grid</h3>
    
    <div class="grid">
      <div class="stamp stamp1"></div>
      <div class="stamp stamp2"></div>
      <div class="grid-item grid-item--width2"></div>
      <div class="grid-item grid-item--height2"></div>
      <div class="grid-item"></div>
      <div class="grid-item"></div>
      <div class="grid-item grid-item--width2 grid-item--height2"></div>
      <div class="grid-item grid-item--width2"></div>
      <div class="grid-item grid-item--width2"></div>
      <div class="grid-item grid-item--height2"></div>
      <div class="grid-item"></div>
      <div class="grid-item grid-item--width2"></div>
      <div class="grid-item grid-item--height2"></div>
      <div class="grid-item"></div>
      <div class="grid-item"></div>
      <div class="grid-item grid-item--width2 grid-item--height2"></div>
      <div class="grid-item"></div>
      <div class="grid-item grid-item--width2"></div>
      <div class="grid-item grid-item--height2"></div>
      <div class="grid-item"></div>
    </div>

    Edit - Workaround #2:

    To handle responsiveness you can change the JavaScript to the following:

    // external js: packery.pkgd.js
    
    var $grid = $('.grid').packery({
      itemSelector: '.grid-item',
      stamp: '.stamp'
    });
    
    function updateCSS(deg) {
      $('.grid').css({
        '-webkit-transform': 'rotate(' + deg + 'deg)',
        'transform': 'rotate(' + deg + 'deg)'
      });
    }
    
    updateCSS(-45);
    
    $(window).resize(function() {
      updateCSS(0);
      $grid.packery('destroy');
      $grid = $('.grid').packery({
        itemSelector: '.grid-item',
        stamp: '.stamp'
      });
      updateCSS(-45);
    });
    

    Updated CodePen #2

    It looks like any call to $grid.packery('layout') after initialization causes problems when the grid is rotated. When the window is resized, it seems like Packery will also recall layout. Therefore, the Packery instance needs to be destroyed and recreated for the rotated grid to display correctly on window resize (basically, overriding Packery's responsive functionality).

    Obviously, this isn't the most ideal solution either - just another workaround.

    You may want to open an issue report on their GitHub page for further assistance: https://github.com/metafizzy/packery/issues