Перенос списков в столбцы

Я использую ColdFusion для заполнения шаблона, который включает HTML списки (<ul> ' s).

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

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

13 ответов


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

другие решения по-прежнему приветствуются.


если поддержка 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;
}

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


насколько я знаю, нет чистого 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">

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

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

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

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

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

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

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

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

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


вот вариант на 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. (Это было очень полезно для меня на стороне сервера, но я не нуждался в нем на клиенте достаточно сильно, чтобы фактически построить его.)

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/> элементы, все элементы должны быть одинаковой высоты, или колонки выйдут из строя.

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

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


чтобы вывести список в несколько сгруппированных тегов, вы можете выполнить цикл таким образом.

<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>

вот еще одно решение, которое позволяет для столбцов списков в следующем стиле:

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

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

следующее содержит некоторый код, который изменяет прототип массива, чтобы дать новую функцию под названием "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);
});

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

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

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>

поскольку у меня была та же проблема и я не мог найти ничего "чистого", я думал, что опубликовал свое решение. В этом примере я использую перевернутую while цикл, поэтому я могу использовать splice вместо slice. Преимущество теперь в том, что splice() нуждается только в индексе и диапазоне, где slice () нуждается в индексе и сумме. Последнее, как правило, становится трудным во время цикла.

недостаток мне нужно обратить стог пока добавление.

пример:

cols = 4; liCount = 35

для петли с кусочком = [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>