将列表包装成列

我正在使用ColdFusion来填充包含HTML列表( <ul> )的模板。

其中大部分时间不长,但有一些长得可笑,可能真的站在2-3列。

有没有HTML,ColdFusion或JavaScript(我有jQuery可用)的方式来做到这一点很容易? 不值得一些过分复杂的重量级解决scheme来保存一些滚动。

所以我从A List Apart CSS Swag:Multi-Column Lists中挖出了这篇文章。 我结束了使用第一个解决scheme,它不是最好的,但其他人需要使用复杂的HTML,不能dynamic生成,或创build了很多自定义类,这可能会做,但会需要大量的内联样式和可能是一个大页面。

其他解决scheme仍然是受欢迎的。

如果Safari和Firefox支持对您来说足够好,那么就有一个CSS解决scheme:

 ul { -webkit-column-count: 3; -moz-column-count: 3; column-count: 3; -webkit-column-gap: 2em; -moz-column-gap: 2em; column-gap: 2em; } 

我不确定Opera。

就我所知,没有纯粹的CSS / HTML方法来实现这一点。 你最好的select是在预处理(如果列表长度> 150,分成3列,如果> 70,分成2列,否则1)。

另一种select是,使用JavaScript(我不熟悉jQuery库)会遍历列表,可能基于它们是一个特定的类,计算子类的数量,如果它是一个足够高的数字,dynamic在第一个之后创build一个新列表,将一些列表项目转移到新列表中。 就实现这些列而言,你可能会将它们左移,然后是一个风格为clear: leftclear: both clear: left的元素。

 .column { float: left; width: 50%; } .clear { clear: both; } 
 <ul class="column"> <li>Item 1</li> <li>Item 2</li> <!-- ... --> <li>Item 49</li> <li>Item 50</li> </ul> <ul class="column"> <li>Item 51</li> <li>Item 52</li> <!-- ... --> <li>Item 99</li> <li>Item 100</li> </ul> <div class="clear"> 

我已经完成了这与jQuery – 这是跨平台和最less的代码。

selectUL,克隆它,然后在之前的UL之后插入它。 就像是:

 $("ul#listname").clone().attr("id","listname2").after() 

这将在上一个之后插入你的清单的副本。 如果原始列表的样式为float:left,则它们应该并排显示。

然后,您可以删除左侧列表中的偶数项目和右侧列表中的奇数项目。

 $("ul#listname li:even").remove(); $("ul#listname2 li:odd").remove(); 

现在你有一个从左到右的两列列表。

要做更多的列,你需要使用.slice(begin,end)和/或:nth-childselect器。 也就是说,对于21个LI,你可以.slice(8,14)在原来的UL之后插入一个新的UL,然后select原始的UL并删除使用ul :gt(8)select的li。

尝试关于jQuery的Bibeault / Katz书籍,这是一个很好的资源。

使用模操作,可以在循环中插入</ul><ul>来快速将列表分割成多个列表。

 <cfset numberOfColumns = 3 /> <cfset numberOfEntries = 34 /> <ul style="float:left;"> <cfloop from="1" to="#numberOfEntries#" index="i"> <li>#i#</li> <cfif NOT i MOD ceiling(numberOfEntries / numberOfColumns)> </ul> <ul style="float:left;"> </cfif> </cfloop> </ul> 

使用ceiling()而不是round()来确保在列表末尾没有额外的值,并且最后一列是最短的。

这里是Thumbkin的例子(使用Jquery)的一个变种:

 var $cat_list = $('ul#catList'); // UL with all list items. var $cat_flow = $('div#catFlow'); // Target div. var $cat_list_clone = $cat_list.clone(); // Clone the list. $('li:odd', $cat_list).remove(); // Remove odd list items. $('li:even', $cat_list_clone).remove(); // Remove even list items. $cat_flow.append($cat_list_clone); // Append the duplicate to the target div. 

感谢Thumbkin!

下面的JavaScript代码只适用于Spidermonkey和Rhino,并且它在E4X节点上运行 – 也就是说,这只对服务器端JavaScript有用,但它可能会给某人一个做jQuery版本的起点。 (这在服务器端对我来说非常有用,但是我并不需要在客户端上实际构build它。)

 function columns(x,num) { num || (num = 2); x.normalize(); var cols, i, j, col, used, left, len, islist; used = left = 0; cols = <div class={'columns cols'+num}></div>; if((left = x.length())==1) left = x.children().length(); else islist = true; for(i=0; i<num; i++) { len = Math.ceil(left/(num-i)); col = islist ? new XMLList : <{x.name()}></{x.name()}>; if(!islist && x['@class'].toString()) col['@class'] = x['@class']; for(j=used; j<len+used; j++) islist ? (col += x[j].copy()) : (col.appendChild(x.child(j).copy())); used += len; left -= len; cols.appendChild(<div class={'column'+(i==(num-1) ? 'collast' : '')}>{col}</div>); } return cols; } 

你把它称为columns(listNode,2)两列,它会变成:

 <ul class="foo"> <li>a</li> <li>b</li> <li>c</li> </ul> 

成:

 <div class="columns cols2"> <div class="column"> <ul class="foo"> <li>a</li> <li>b</li> </ul> </div> <div class="column collast"> <ul class="foo"> <li>c</li> </ul> </div> </div> 

这意味着像这样使用CSS:

 div.columns { overflow: hidden; _zoom: 1; } div.columns div.column { float: left; } div.cols2 div.column { width: 47.2%; padding: 0 5% 0 0; } div.cols3 div.column { width: 29.8%; padding: 0 5% 0 0; } div.cols4 div.column { width: 21.1%; padding: 0 5% 0 0; } div.cols5 div.column { width: 15.9%; padding: 0 5% 0 0; } div.columns div.collast { padding: 0; } 

大多数人忘记的是,当浮动<li/>项目时,所有的项目必须是相同的高度,或列开始摆脱重击。

由于您使用的是服务器端语言,我的build议是使用CF将列表分成3个数组。 然后你可以使用一个外部ul来包装3个内部ul就像这样:

 <cfset thelist = "1,2,3,4,5,6,7,8,9,10,11,12,13"> <cfset container = []> <cfset container[1] = []> <cfset container[2] = []> <cfset container[3] = []> <cfloop list="#thelist#" index="i"> <cfif i mod 3 eq 0> <cfset arrayappend(container[3], i)> <cfelseif i mod 2 eq 0> <cfset arrayappend(container[2], i)> <cfelse> <cfset arrayappend(container[1], i)> </cfif> </cfloop> <style type="text/css"> ul li { float: left; } ul li ul li { clear: left; } </style> <cfoutput> <ul> <cfloop from="1" to="3" index="a"> <li> <ul> <cfloop array="#container[a]#" index="i"> <li>#i#</li> </cfloop> </ul> </li> </cfloop> </ul> </cfoutput> 

要将列表输出到多个分组标签中,您可以按照这种方式进行循环。

 <cfset list="1,2,3,4,5,6,7,8,9,10,11,12,13,14"> <cfset numberOfColumns = "3"> <cfoutput> <cfloop from="1" to="#numberOfColumns#" index="col"> <ul> <cfloop from="#col#" to="#listLen(list)#" index="i" step="#numberOfColumns#"> <li>#listGetAt(list,i)#</li> </cfloop> </ul> </cfloop> </cfoutput> 

这是另一个解决scheme,允许列出以下风格的列表:

 1. 4. 7. 10. 2. 5. 8. 11. 3. 6. 9. 12. 

(但它是纯粹的JavaScript,并要求jQuery,没有后备)

下面包含一些修改数组原型的代码,给出一个名为“chunk”的新函数,它将给定的数组分割成给定大小的块。 接下来是一个名为“buildColumns”的函数,它接受一个ULselect器string和一个数字,用来指定列中可能包含的行数。 ( 这是一个可用的JSFiddle )

 $(document).ready(function(){ Array.prototype.chunk = function(chunk_size){ var array = this, new_array = [], chunk_size = chunk_size, i, length; for(i = 0, length = array.length; i < length; i += chunk_size){ new_array.push(array.slice(i, i + chunk_size)); } return new_array; } function buildColumns(list, row_limit) { var list_items = $(list).find('li').map(function(){return this;}).get(), row_limit = row_limit, columnized_list_items = list_items.chunk(row_limit); $(columnized_list_items).each(function(i){ if (i != 0){ var item_width = $(this).outerWidth(), item_height = $(this).outerHeight(), top_margin = -((item_height * row_limit) + (parseInt($(this).css('margin-top')) * row_limit)), left_margin = (item_width * i) + (parseInt($(this).css('margin-left')) * (i + 1)); $(this[0]).css('margin-top', top_margin); $(this).css('margin-left', left_margin); } }); } buildColumns('ul#some_list', 5); }); 

Flexbox可用于在行和列方向上包装项目。

主要想法是将容器的flex-direction设置为rowcolumn

NB:现在的浏览器支持相当不错。

小提琴

(从这个旧的'列表分类'文章中的样本标记)

 ol { display: flex; flex-flow: column wrap; /* flex-direction: column */ height: 100px; /* need to specify height :-( */ } ol ~ ol { flex-flow: row wrap; /* flex-direction: row */ max-height: auto; /* override max-height of the column direction */ } li { width: 150px; } a { display: inline-block; padding-right: 35px; } 
 <p>items in column direction</p> <ol> <li><a href="#">Aloe</a> </li> <li><a href="#">Bergamot</a> </li> <li><a href="#">Calendula</a> </li> <li><a href="#">Damiana</a> </li> <li><a href="#">Elderflower</a> </li> <li><a href="#">Feverfew</a> </li> <li><a href="#">Ginger</a> </li> <li><a href="#">Hops</a> </li> <li><a href="#">Iris</a> </li> <li><a href="#">Juniper</a> </li> <li><a href="#">Kava kava</a> </li> <li><a href="#">Lavender</a> </li> <li><a href="#">Marjoram</a> </li> <li><a href="#">Nutmeg</a> </li> <li><a href="#">Oregano</a> </li> <li><a href="#">Pennyroyal</a> </li> </ol> <hr/> <p>items in row direction</p> <ol> <li><a href="#">Aloe</a> </li> <li><a href="#">Bergamot</a> </li> <li><a href="#">Calendula</a> </li> <li><a href="#">Damiana</a> </li> <li><a href="#">Elderflower</a> </li> <li><a href="#">Feverfew</a> </li> <li><a href="#">Ginger</a> </li> <li><a href="#">Hops</a> </li> <li><a href="#">Iris</a> </li> <li><a href="#">Juniper</a> </li> <li><a href="#">Kava kava</a> </li> <li><a href="#">Lavender</a> </li> <li><a href="#">Marjoram</a> </li> <li><a href="#">Nutmeg</a> </li> <li><a href="#">Oregano</a> </li> <li><a href="#">Pennyroyal</a> </li> </ol> 

由于我有同样的问题,找不到任何“干净”,我想我已经发布了我的解决scheme。 在这个例子中,我使用了一个反转的while循环,所以我可以使用splice而不是slice 。 现在的优势是splice()只需要一个索引和一个范围,其中slice()需要索引和总数。 后者往往变得困难,而循环。

缺点是我需要在追加时反转堆栈。

例:

cols = 4; liCount = 35

for循环与切片= [0,9]; [9,18]; [18,27]; [27,35]

当拼接= [27,8]时颠倒; [18,9]; [9,9]; [0,9]

码:

 // @param (list): a jquery ul object // @param (cols): amount of requested columns function multiColumn (list, cols) { var children = list.children(), target = list.parent(), liCount = children.length, newUl = $("<ul />").addClass(list.prop("class")), newItems, avg = Math.floor(liCount / cols), rest = liCount % cols, take, stack = []; while (cols--) { take = rest > cols ? (avg + 1) : avg; liCount -= take; newItems = children.splice(liCount, take); stack.push(newUl.clone().append(newItems)); } target.append(stack.reverse()); list.remove(); } 

你可以尝试这个转换成cols。

CSS:

 ul.col { width:50%; float:left; } div.clr { clear:both; } 

Html部分:

 <ul class="col"> <li>Number 1</li> <li>Number 2</li> <li>Number 19</li> <li>Number 20</li> </ul> <ul class="col"> <li>Number 21</li> <li>Number 22</li> <li>Number 39</li> <li>Number 40</li> </ul>