Tuesday, November 19, 2013

Grid of elements with variable heights and a sorted order

Assumptions
You have a grid of elements each with a fixed width and a variable height. Example. Images that have fixed width and a variable height because you want to preserve the aspect ratio.

The problem you want to align them into a grid but simple floating them leaves large gaps in vertical space between elements.

Great further explanation of the problem, taken from link below.

"To my knowledge, there's no way to fix this problem with pure CSS (that works in all common browsers):
  • Floats don't work.
  • display: inline-block doesn't work.
  • position: relative with position: absolute requires manual pixel tuning. If you're using a server-side language, and you're working with images (or something with predictable height), you can handle the pixel tuning "automatically" with server-side code.
Instead, use jQuery Masonry."

http://stackoverflow.com/questions/5234749/css-floating-divs-at-variable-heights

Solutions

1. This sorts the elements by height.

 $('.arrange').each(function(){
            arrange.elements.push(new Array($(this).height(), $(this).clone()));
         
        });
 for(var i = 0; i < arrange.elements.length; i ++)
        {
          if(arrange.elements[i][0] > current)
          {
              current = arrange.elements[i][0];
              elem = arrange.elements[i][1];
              index = i;
          }
        }

This is pretty slow by the way.
http://jsfiddle.net/hMmLd/1/

2. Use jquery masonry or isotope

http://masonry.desandro.com/
http://isotope.metafizzy.co/

http://jsfiddle.net/RXDL4/406/

3. Absolute positioning

Jquery Waterfall Plugin
http://wlog.cn/waterfall/

4. Solution we settled on after playing with all of the above techniques.

We organize the elements into their respective sections one for each column, this way we can both insert sorted data into them and preserve reasonable vertical spacing.

So for n columns you would have markup like the following.

<section class="mediaItems overview" data-bind="foreach: columns">
<div class="column-div" data-bind="unveil: $root.everyNthMediaItems($index())">
<img data-bind=" attr: { src: url}" />
                </div>
</section>

We precompute the items that will be in each column to make it faster loading on the dom aka (everyNthMediaItems). That way we start with sorted data and then run everyNthMediaItems to put that data into columns thereby preserving the sorting and keeping vertical spacing correct.

                       


No comments:

Post a Comment