Pregunta

Estoy usando ColdFusion para completar una plantilla que incluya HTML listas (<ul>'s).

La mayoría de estos no son tan largos, pero algunos tienen longitudes ridículamente largas y realmente podrían estar en 2 o 3 columnas.

Hay un HTML, ColdFusion o quizás JavaScript (Tengo jQuery` disponible) ¿manera de hacer esto fácilmente?No vale la pena utilizar una solución pesada y demasiado complicada para ahorrar algo de desplazamiento.

¿Fue útil?

Solución

Así que desenterré este artículo de A List Apart. Botín CSS:Listas de varias columnas.Terminé usando la primera solución, no es la mejor, pero las otras requieren el uso de HTML complejo que no se puede generar dinámicamente o la creación de muchas clases personalizadas, lo que podría hacerse pero requeriría muchos estilos en línea y Posiblemente una página enorme.

Sin embargo, otras soluciones siguen siendo bienvenidas.

Otros consejos

Si la compatibilidad con Safari y Firefox es lo suficientemente buena para usted, existe una solución CSS:

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

No estoy seguro acerca de Opera.

Hasta donde yo sé, no existe una forma pura de CSS/HTML para lograr esto.Su mejor opción sería hacerlo en el preprocesamiento (if list length > 150, split into 3 columns, else if > 70, split into 2 columns, else 1).

La otra opción, usar JavaScript (no estoy familiarizado con el jQuery biblioteca específicamente) sería iterar a través de listas, probablemente basándose en que son una determinada clase, contar el número de elementos secundarios y, si es un número lo suficientemente alto, crear dinámicamente una nueva lista después de la primera, transfiriendo una cierta cantidad de elementos de la lista a la nueva lista.En cuanto a implementar las columnas, probablemente podrías hacerlas flotar hacia la izquierda, seguidas de un elemento que tuviera el estilo clear: left o 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">

Hice esto con jQuery: es multiplataforma y tiene un mínimo de código.

Seleccione el UL, clónelo e insértelo después del UL anterior.Algo como:

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

Esto insertará una copia de su lista después de la anterior.Si la lista original tiene el estilo flotante: izquierda, deberían aparecer uno al lado del otro.

Luego puede eliminar los elementos pares de la lista de la izquierda y los elementos impares de la lista de la derecha.

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

Ahora tiene una lista de dos columnas de izquierda a derecha.

Para hacer más columnas querrás usar .slice(begin,end) y/o el :nth-child selector.es decir, por 21 LI podrías .slice(8,14) para crear una nueva UL insertada después de su UL original, luego seleccione la UL original y elimine los li seleccionados con ul :gt(8).

Pruebe el libro de Bibeault/Katz sobre jQuery, es un gran recurso.

Aquí hay una variación de Pulgarcitos ejemplo (usando 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.

¡Gracias Pulgarcito!

El siguiente código JavaScript funciona solo en Spidermonkey y Rhino, y opera en nodos E4X; es decir, esto es útil solo para JavaScript del lado del servidor, pero podría brindarle a alguien un punto de partida para hacer una versión jQuery.(Ha sido muy útil para mí en el lado del servidor, pero no lo he necesitado tanto en el cliente como para compilarlo).

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

lo llamas como columns(listNode,2) para dos columnas, y resulta:

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

en:

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

Está destinado a usarse con CSS de esta manera:

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

Lo que la mayoría de la gente olvida es que cuando flotas <li/> elementos, todos los elementos deben tener la misma altura, o las columnas comenzarán a descontrolarse.

Dado que está utilizando un lenguaje del lado del servidor, mi recomendación sería utilizar CF para dividir la lista en 3 matrices.Entonces puedes usar un exterior. ul para envolver los 3 interiores ul al igual que:

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

Usando una operación de módulo, puede dividir rápidamente su lista en varias listas insertando un </ul><ul> durante su ciclo.

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

Usar ceiling() en lugar de round() para asegurarse de que no tenga valores adicionales al final de la lista y que la última columna sea la más corta.

Para generar la lista en varias etiquetas agrupadas, puede realizar un bucle de esta manera.

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

Aquí hay otra solución que permite listas con columnas en el siguiente estilo:

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

(pero es javascript puro y requiere jQuery, sin respaldo)

Lo siguiente contiene un código que modifica el prototipo de Array para proporcionar una nueva función llamada 'fragmento' que divide cualquier Array en trozos de un tamaño determinado.La siguiente es una función llamada 'buildColumns' que toma una cadena de selección UL y un número usado para designar cuántas filas pueden contener sus columnas.(Aquí hay un JSFiddle funcional)

$(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 se puede utilizar para ajustar elementos tanto en dirección de fila como de columna.

La idea principal es establecer el flex-direction en el contenedor a cualquiera row o column.

NÓTESE BIEN:Hoy en día soporte del navegador es bastante bueno.

VIOLÍN

(Marcado de muestra tomado de este viejo artículo de 'lista aparte')

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>

Como tuve el mismo problema y no pude encontrar nada "limpio", pensé que había publicado mi solución.En este ejemplo utilizo un invertido while bucle para que pueda usar splice en lugar de slice.La ventaja ahora es que splice() solo necesita un índice y un rango donde slice() necesita un índice y el total.Esto último tiende a resultar difícil mientras se realiza el bucle.

La desventaja es que necesito invertir la pila mientras la agrego.

Ejemplo:

columnas = 4;liCount = 35

bucle for con segmento = [0, 9];[9, 18];[18, 27];[27, 35]

invertido mientras con empalme = [27, 8];[18, 9];[9, 9];[0, 9]

Código:

// @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();
}

Puedes probar esto para convertir en cols.

CSS:

ul.col {
    width:50%;
    float:left;
}

div.clr {
    clear:both;
}

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

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top