Подтвердить что ты не робот

Объединение списков в столбцы

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

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

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

4b9b3361

Ответ 1

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

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

Ответ 2

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

Я не уверен в Opera.

Ответ 3

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

Ответ 4

Я сделал это с помощью 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 LI вы могли бы .slice(8,14) создать новый UL, вставленный после вашего исходного UL, затем выбрать исходный UL и удалить li, выбранный с помощью ul :gt(8).

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

Ответ 5

Следующий код 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;
}

Ответ 6

То, что большинство людей забывает, заключается в том, что при плавающих элементах <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>

Ответ 7

Ниже приведен пример варианта Thumbkin's (с использованием 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!

Ответ 8

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

Ответ 9

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

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

Ответ 10

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

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);
});

Ответ 11

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

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

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

FIDDLE

(Пример разметки, взятой из этой старой статьи, посвященной списку)

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>

Ответ 12

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

Ответ 13

Вы можете попробовать это преобразовать в 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>