瀑布流布局

如果你经常网上冲浪,这样参差不齐的多栏布局,是不是很眼熟啊?

类似的布局,似乎一夜之间出现在国内外大大小小的网站上,比如 Pinterest (貌似是最早使用这种布局的网站了),Mark之蘑菇街点点网,以及淘宝最新上线的“哇哦” 等等,倒是很流行哈~ 在淘宝即将上线的众多产品中,你还会大量看到这样的形式呢。

这种布局适合于小数据块,每个数据块内容相近且没有侧重。通常,随着页面滚动条向下滚动,这种布局还会不断加载数据块并附加至当前尾部。所以,我们给这样的布局起了一个形象的名字 — 瀑布流式布局。dynamic grid layout

http://www.fengxiaoqiang.com/blog/2011/11/%E7%80%91%E5%B8%83%E6%B5%81%E5%B8%83%E5%B1%80%E6%B5%85%E6%9E%90.html#more-1049

http://ued.taobao.com/blog/2011/09/14/waterfall/

http://www.yixieshi.com/ucd/10513.html

http://www.im9527.com/archives/8

http://webdesigninspirationtoday.com/article/367/5-jquery-plugins-to-produce-pinterest-like-dynamic-grid-layout

下面的这篇文章来自:http://miksovsky.blogs.com/flowstate/2012/03/packedcolumns.html

Image-sharing site Pinterest is the current darling of the social media world, and the core of its user experience is its attractively-designed home page:

Pinterest

This page takes good advantage of available window real estate. As the user makes the window wider, the page re-lays out the columns of image tiles (or “pins”, in the parlance of the site) to take advantage of the extra

Pinterest (Wider)

The page must accommodate a wide range of tile heights, as the photos have different aspect ratios, and the number of comments per pin can vary. If the page simply laid out the tiles in a strict grid, it would waste a great deal of space. To use the space more efficiently, the page employs a “packed columns” layout.

Key attributes

The packed columns layout algorithm is straightforward:

  1. Divide available width by the standard item width to determine how many columns can fit.
  2. Make all columns initially empty.
  3. For each item in turn, add the item to the column which is currently shortest.

The simplicity of this algorithm is such that it’s been independently recreated multiple times. The algorithm has some nice properties:

  • It’s fast.
  • As much horizontal space is used as possible (while still showing entire items). If a user gives the site more width, they’re rewarded with more information.
  • The arrangement is visually interesting.
  • The positions of the first few items are stable.
  • At any given page width, the overall heights of the columns will be roughly equivalent. If the user scrolls to the bottom, they won’t find an unbalanced amount of space under any particular column.
  • The relative vertical position of any two items is preserved across resize operations. If item A appears above item B at one window size, then item A will always be above (or on the same row) as item B at any other window size. The user doesn’t need to understand this; it just means that if some interesting item is “near the top” before a resize, then after the resize the same interesting item will still be “near the top”.

The last point speaks to another benefit of the algorithm which doesn’t show up in Pinterest, but does show up in other applications: the consistent relative positions of items means you can offer users the ability to specify an order or prioritization for the items that affects (but doesn’t completely determine) where items end up. I used this years ago in the design for a home page for Microsoft Money, a personal finance application whose home page included a user-customizable set of home page modules. A Settings dialog let the user specify the priority of those modules by dragging the modules within a one-dimensional list. While the ultimate two-dimensional position of the modules depended on the window width and the modules’ current heights, the priority of any given module determined how close to the top of the page that module would end up. This limited degree of customization was sufficient to meet many users’ needs without having to create a full-blown customizable layout UI.

PackedColumns

I’ve added a PackedColumns control to the QuickUI Catalog. There’s a link to a demo that simulates the general appearance of Pinterest’s home page. (I initially centered the items in the demo the way Pinterest does, but turned centering off to make it easier to observe the layout behavior.)

Usage: Use PackedColumns to arrange a collection of child elements whose widths are fixed but whose heights vary substantially. If the heights are relatively consistent, users will likely find a traditional grid presentation easier to interpret and use.

Commentary

Given the simplicity of the algorithm, this wasn’t all that hard to code up. I expect it’s not necessarily the actual cost of a layout like this that deters sites from adopting it. Rather, it’s the current need to independently discover or reverse-engineer behavior like this that most inhibits its adoption. As design knowledge gets coded into controls, however, such UI should become more pervasive.

In essence, an ability to easily create and adopt create web components will lead to a commodification of user interface elements. Today Pinterest’s insight and ability to create a packed columns layout may confer a slight competitive edge, but someday commodification will quickly eliminate such edges. This will be true not just for UI elements that can easily be independently created, but for nearly anything. The day after a new site launches with a cool new UI trick, that trick will be copied and packaged up as an openly available and readily adoptable UI control anyone can use.

另一篇:

http://benholland.me/javascript/how-to-build-a-site-that-works-like-pinterest/

How To Build A Site That Works Like Pinterest

Ok, if you have no idea what Pinterest is then go check it out. It is a website that lets you organise and share all your favourite things by using pinboards. It really is a cool site, but what I find interesting is how these pinboards are laid out. I’ve seen something similar before with jQuery Isotope where blocks are perfectly positioned into a series of columns, and as the screen size changes, the columns re-shuffle to make sure they fit inside the screen. So the purpose of this tutorial is to re-create this responsive block effect ourselves…

The Theory

Right, before jumping into the code, we need to get the theory sorted in our heads. It’s a relatively simple system once you grasp the concept. To make this system work, we first need to know 3 things; the window width, the width of the blocks and the margin between these blocks.

From this data, we then calculate the number of possibly blocks that would fit in the window. This gives us our number of columns, so in the diagram above, it would be 4. So we create an array with 4 values in, defaulted at the value of the margin. This array is used to store the running heights of each column. E.g. a block of height 120px is added to column 3, so that value in the array is increased by 120. We also use the index number of each value to calculate the position from the left of the screen. Here’s a flow diagram of how the function will work. This will also run everytime the window is resized so the blocks can update themselves.

Setting Up The Blocks

So there’s some information about the theory behind both Pinterest and jQuery Isotope. If it didn’t make much sense then hopefully getting stuck into some code will help. To start, we need a simple HTML structure. From this HTML, we need to grab 3 vital values; the window width, the width of the blocks and the margin between the blocks.

The HTML Structure

<body onload="setupBlocks();">
    <!-- Create multiple versions of this with different content -->
    <div class="block">
        <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut in dui velit. Curabitur purus odio, adipiscing ut vehicula at, pulvinar eu justo. Suspendisse potenti. Suspendisse dictum massa non mi posuere ac convallis nisi pellentesque. Morbi posuere mauris elementum metus intlla faProin et malesuada arcu. Quisque sed nulla odio, at interdum diam. Proin mollis, dui eget tristique dictum, diam purus hendrerit urna, lacinia interdum sem justo sit amet justo. Morbi a neque ut velit tempus auctor. Sed condimentum dolor in est facilisis id malesuad</p>
    </div>
</body>
.block {
    position: absolute;
    background: #eee;
    padding: 20px;
    width: 300px;
    border: 1px solid #ddd;
}

jquery

var colCount = 0;
var colWidth = 0;
var margin = 20;
var windowWidth = 0;
var blocks = [];

function setupBlocks() {
    windowWidth = $(window).width();
    colWidth = $('.block').outerWidth();
    colCount = Math.floor(windowWidth/(colWidth+margin));
    for(var i=0;i<colCount;i++) {
        blocks.push(margin);
    }
    alert(blocks);
}

Positioning The Blocks

Did you notice what was happening?? When the window was smaller, there were less number of values in the array. This is because there were less columns that would fit into the window.

Now we’ve set up our blocks and have an array of the starting heights of each column. So now we’re just left to determining the position of each block. Here’s the function, I’ll go into more detail afterwards…#

function positionBlocks() {
    $('.block').each(function(){
        var min = Array.min(blocks);
        var index = $.inArray(min, blocks);
        var leftPos = margin+(index*(colWidth+margin));
        $(this).css({
            'left':leftPos+'px',
            'top':min+'px'
        });
        blocks[index] = min+block.outerHeight()+margin;
    });
}

// Function to get the Min value in Array
Array.min = function(array) {
    return Math.min.apply(Math, array);
};
$(window).resize(setupBlocks);

So that is it really. You should have system that looks and works just like Pinterest and jQuery Isotope. Another good addition is to add this to ‘block’ class in your CSS:

-webkit-transition: all 1s ease-in-out;
-moz-transition: all 1s ease-in-out;
-o-transition: all 1s ease-in-out;
-ms-transition: all 1s ease-in-out;
transition: all 1s ease-in-out;


Check out the finished code here

Also, check out the demo that keeps the blocks centered in the screen

上面的代码并没有真正居中,下面的代码可以真正居中:

画图示意:

 colCount = Math.floor(windowWidth/(colWidth+margin*2));
   
    spaceLeft=(windowWidth-(colWidth+2*margin)*colCount )/2;
 'left':(leftPos+spaceLeft)+'px',

<style type="text/css">
.block{
    position:absolute;
    background:#eee;
    padding:20px;
    width:300px;
    border:1px solid #ddd;
}
</style>
 <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
 
<script type="text/javascript">
var colCount=0;
var colWidth=0;
var margin=20;
var windowWidth=0;
var spaceLeft=0;
var blocks=[];
function setupBlocks()
{
     
    windowWidth = $(window).width();
    colWidth=$('.block').outerWidth();
    blocks=[];//一定要
    // Calculate the margin so the blocks are evenly spaced within the window
    colCount = Math.floor(windowWidth/(colWidth+margin*2));
    
    spaceLeft=(windowWidth-(colWidth+2*margin)*colCount )/2;
    
    console.log(spaceLeft);
    
    for(var i=0;i<colCount;i++){
        blocks.push(margin);
    }
    positionBlocks();
    
    
};
function positionBlocks()
{
 
    $('.block').each(function(i){
        var min = Array.min(blocks);
        var index = $.inArray(min, blocks);
        var leftPos = margin+(index*(colWidth+2*margin));
        $(this).css({
            'left':(leftPos+spaceLeft)+'px',
            'top':min+'px'
        });
        blocks[index] = min+$(this).outerHeight()+margin;
    });    
}
$(document).ready(function(e) {
     
         setupBlocks();
          $(window).resize(setupBlocks);
});    

 //onload="setupBlocks()"
Array.min=function(array){
    return Math.min.apply(Math,array);
}
</script>

 绝对定位:

优点:
· 方便添加数据内容,窗口变化,列数/数据块都会自动调整;
缺点:
· 需要知道数据块高度,如果其中包含图片,需要知道图片高度;
· JS 动态计算数据块位置,当窗口缩放频繁,可能会狂耗性能。
 

JS实现的主要思路:

有兴趣的同学可以看一下:
一个是对现有数据块进行排列计算各自所在的位置; 二是下拉滚动时,触发加载数据操作,并把数据添加到目标容器中。
1) 数据块排列,算法步骤简述下:
· 初始化时,对容器中已有数据块元素进行第一次计算,需要用户给定: a,容器元素 — 以此获取容器总宽度; b,列宽度; c,最小列数;
· 最终列数取的是容器宽度/列宽度和最小列数的最大值,这样保证了,当窗口很小时,仍然出现最小列数的数据;
· 获得列数后,需要保存每个列的当前高度,这样在添加每个数据块时,才知道起始高度是多少;
· 依次取容器中的所有数据块,先寻找当前高度最小的某列,之后根据列序号,确定数据块的left,top值,left 为所在列的序号乘以列宽,top 为所在列的当前高度,最后更新所在列的当前高度加上这个数据块元素的高度,至此,插入一个元素结束;
· 当所有元素插入完毕后,调整容器的高度为各列最大的高度值,结束依次调整;
· 性能效率上的注意点: a,如果当前正在调整中,又触发了 resize 事件,需要将上次调整暂停后执行这次调整(见 timedChunk 函数); b,resize 触发会很频繁,可以将回调函数缓存一段时候后执行,即当这段时间内多次触发了resize事件,但回调函数只会执行一次(见 S.buffer 函数)
2) 异步加载数据,前面讲的是如何对容器中已有元素进行排列,但很多情况下,还需要不断加载新数据块,其实这个功能块也并不复杂,仅包含两个步骤:
· 绑定滚动事件,并确定预加载线高度值,即滚动到哪个高度后,需要去加载数据,其实这个就是列的最小高度值,这样当前滚动值和最小高度值比较一下即可判断出来,是否要触发加载数据;
· 加载数据,函数传参,能提供加载数据函数和停止加载(加载多少时停止)函数,以更方便的控制

 

原文地址:https://www.cnblogs.com/youxin/p/2645452.html