Упаковка списков в столбцы - PullRequest
51 голосов
/ 07 августа 2008

Я использую ColdFusion для заполнения шаблона, включающего HTML списки (<ul>).

Большинство из них не такие длинные, но некоторые имеют смехотворно большую длину и могут стоять в 2-3 столбца.

Есть ли HTML, ColdFusion или, возможно, JavaScript (у меня есть jQuery`) способ сделать это легко? Это не стоит слишком сложного и тяжеловесного решения, чтобы сэкономить на прокрутке.

Ответы [ 13 ]

24 голосов
/ 07 августа 2008

Итак, я выкопал эту статью из A List Apart CSS Swag: Многостолбцовые списки . Я закончил тем, что использовал первое решение, оно не самое лучшее, но другие требуют либо использования сложного HTML, который не может быть сгенерирован динамически, либо создания множества пользовательских классов, что может быть сделано, но потребует загрузки встроенных стилей и возможно огромная страница.

Другие решения все еще приветствуются.

15 голосов
/ 08 августа 2008

Если поддержка Safari и Firefox вам подходит, есть решение CSS:

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

Я не уверен насчет Оперы.

9 голосов
/ 07 августа 2008

Насколько я знаю, не существует чистого способа CSS / HTML для достижения этой цели. Лучше всего сделать это при предварительной обработке (if list length > 150, split into 3 columns, else if > 70, split into 2 columns, else 1).

Другой вариант, использующий JavaScript (я не знаком с библиотекой jQuery ), - перебирать списки, вероятно, на основе того, что они являются определенным классом, подсчитывать количество детей и если это достаточно большое число, динамически создайте новый список после первого, перенося некоторое количество элементов списка в новый список. Что касается реализации столбцов, вы, вероятно, могли бы перемещать их влево, следуя за элементом, который имел стиль clear: left или clear: both.

.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">
5 голосов
/ 17 сентября 2008

Я сделал это с помощью jQuery - это кроссплатформенность и минимум кода.

Выберите UL, клонируйте его и вставьте после предыдущего UL. Что-то вроде:

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

Это вставит копию вашего списка после предыдущего. Если исходный список имеет стиль с плавающей точкой: слева, они должны отображаться рядом.

Затем вы можете удалить четные элементы из списка слева и нечетные элементы из списка справа.

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

Теперь у вас есть два столбца слева направо.

Чтобы сделать больше столбцов, вам нужно использовать .slice(begin,end) и / или селектор :nth-child. т. е. для 21 LI вы можете .slice(8,14) создать новый UL, вставленный после вашего исходного UL, затем выбрать исходный UL и удалить выбранные li с помощью ul :gt(8).

Попробуйте книгу Bibeault / Katz на jQuery, это отличный ресурс.

4 голосов
/ 21 декабря 2009

Вот вариант примера 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!

4 голосов
/ 17 сентября 2008

Большинство людей забывают о том, что при перемещении <li/> элементов все элементы должны иметь одинаковую высоту, или столбцы начинают выходить из строя.

Поскольку вы используете язык на стороне сервера, я бы рекомендовал использовать 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>
4 голосов
/ 15 сентября 2008

Следующий код JavaScript работает только в Spidermonkey и Rhino и работает на узлах E4X - т.е. это полезно только для серверного JavaScript, но может дать кому-то отправную точку для создания версии jQuery. (Это было очень полезно для меня на стороне сервера, но мне не нужно было это на клиенте достаточно сильно, чтобы на самом деле построить его.)

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;
}
3 голосов
/ 21 сентября 2008

Используя операцию по модулю, вы можете быстро разбить свой список на несколько списков, вставив </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(), чтобы убедиться, что у вас нет дополнительных значений в конце списка и что последний столбец самый короткий.

2 голосов
/ 30 августа 2015

Flexbox можно использовать для упаковки элементов в направлениях строк и столбцов.

Основная идея состоит в том, чтобы установить flex-direction на контейнере либо row, либо column.

Примечание: в настоящее время поддержка браузера довольно хороша.

FIDDLE

(Пример разметки, взятой из этой старой статьи 'list обособленно' )

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>
2 голосов
/ 30 января 2013

Вот еще одно решение, позволяющее создавать колонные списки в следующем стиле:

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

(но это чистый javascript и требует jQuery, без отступления)

Следующее содержит некоторый код, который модифицирует прототип Array, чтобы дать новую функцию с именем 'chunk', которая разбивает любой данный массив на куски заданного размера. Далее идет функция с именем buildColumns, которая принимает строку селектора UL и число, используемое для определения количества строк, которые могут содержать ваши столбцы. ( Вот рабочий 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);
});
...