en CSS

Columnas CSS

Actualización: este artículo es anterior al lanzamiento de IE8 pero explica la técnica de «réplica de una tabla» que sigue siendo un método válido y efectivo para montar una estructura table-free de columnas mediante CSS.

Crear una estructura de columnas con css y html sin usar tablas Desde que comencé en este mundo del marcado con etiquetas de hipertexto, muchas veces tuve la necesidad de construir una estructura de 2 o 3 columnas. El problema llegó cuando me inicié en estructuras semánticas y vi que quizás el uso de tablas no era el más propicio puesto que me restaba flexibilidad estilística y accesibilidad. Fue entonces cuando comencé a buscar soluciones ajenas sin encontrar ninguna que me satisficiera y no pude evitar embarcarme en la búsqueda de las mías propias.
Lo primero que hice fue plantear la estructura e intentar partir de la solución parcial que todos usábamos ya para construir columnas. Tenemos una caja principal con dos elementos embebidos que queremos se comporten como columnas…

fase0

crosbrowsing fase inicial

Normalmente usaríamos un float en la primera columna para flotar el contenido de la segunda pero eso no nos daría dos culumnas del mismo tamaño sino algo así:

crosbrowsing pimer paso

crosbrowsing pimer paso

Vemos dos problemas,  el primero es el ya clásico problema de los floats. Para solucionarlo podríamos usar las múltiples opciones que nos han proporcionado los gurus, sin embargo para este ejercicio aplicaremos un display-table al contenedor y de ese modo el contenido no desbordará la caja. Para solucionar el segundo de ellos necesitamos ir a la raíz del problema: estamos usando un atributo cuyo fin es flotar contenido en linea al rededor del elemento al cual se le ha aplicado. No parece que sea el mismo que el nuestro, que es crear una estructura de columnas o celdas paralela. Os propongo dos soluciones.

  1. La solución con display table y height inherit(FF)/100%(IE)
    Compatibilidad:

    • Gecko (FF): 95%
    • Webkit (Safari, Chrome): 80%
    • Presto (Opera):30%
    • Trident (IE): 60%

    Bugs:

    1. En WebKit, Presto y Trident, al depender de la altura heredada de la ventana por medio del tag <html> una vez superada esa altura por alguna de las columnas, las otras no seguirán creciendo a pesar de que lo haga su contenedor, e incluso pueden llegar a perder la herencia por completo.
    2. IE necesitará una excepción para sustituir height: inherit por height: 100%
    3. Los navegadores basados en Webkit pueden sufrir conflictos cuando la caja contenedora esté alojada dentro de otras
    4. Opera se comporta como IE pero puesto que no podemos hacer excepciones para ella, su compatibildad con el método es nula.
    5. En WebKit al usar padding o border en modo tabla aparecen diferencias en el modelo de caja. Sin embargo se pueden aplicar a los elementos interiores sin problemas

    Comentarios: aunque algo compleja, es la única solución mínimamente compatible con IE7 o inferiores.

  2. Solución mediante la replica de una tabla
    Compatibilidad:

    • Gecko (FF): 100%
    • Webkit (Safari, Chrome): 100%
    • Presto (Opera): 100%
    • Trident (IE): 0%
    • IE8: próximanente

    Bugs: al igual que el float el método display: table-cell puede no renderizarse en FF ante cargas extremadamente  lentas.
    Comentarios: Rápido y sencillo de implementar. No tiene secretos y es soportado por todos los navegadores excepto IE7 o inferiores ya que no reconocen display: table.

La solución con display table y height inherit(FF)/100%(IE)

En esta solución aprovechamos los floats, y digo floats porque nos hará falta flotar ambas columnas y además proporcionarle el ancho a ambas tambien.
Probrar solución para FF y cia. en directo

  1. Lo primero que hacemos es aplicar nuestro display table al elemento contenedor para que los elementos flotados no desborden.
    <div style="display: table;width: 402px; padding: 2px">
      <div style="float: left; width: 250px; background-color: #666;">Columna 1</div>
      <div style="float: left; width: 150px; background-color: #f40;">Columna 2</div>
    </div> 

    crossbrowsing paso 2

    crossbrowsing segundo paso

  2. Vemos que la altura de ambas columnas no se equipara, de modo que racionalicemos el problema. Necesitamos que, haya las columnas que haya, todas igualen su altura a la de la más alta de ellas. ¿Cual es el elemento que siempre tendrá la altura máxima? Si cualquiera de las columnas puede crecer en función de su contenido, sólo hay un elemento que ahora se está acomodando a la altura de la mayor de las columnas: el contenedor. Es pues su altura la que nos importa, y los estándares nos permiten trasmitirle esta altura a sus elementos hijo mediante la herencia. Pero como no iba a ser tan fácil, primero tendremos que declarale una altura al contenedor por CSS para que sus hijos la puedan heredar. Y he aquí el dilema. Veamos primero el resultado con una medida fija.
    <div style="display: table; width: 402px; height:60px; padding: 2px 0px 2px 2px;">
      <div style="float: left; width: 250px; height: inherit; background-color: #666;">Columna 1</div>
      <div style="float: left; width: 150px; height: inherit; background-color: #f40;">Columna 2</div>
    </div>

    crossbrosing tercer paso

    crossbrowsing tercer paso

  3. Lo ideal sería que no tuviésemos que proporcionarle un alto al contenedor sino que éste creciese y automáticamente tomase un valor.  Como esto no es así y proporcionarle un alto fijo nos sirve de poco,  la única solución posible es dotarlo de un alto porcentual. Aunque no sea tampoco lo ideal pues nos obliga a tener un álto mínimo esta solución tiene truco. En principio podemos creer que nuestros <body> cubre el 100% de la ventana, pero eso no es así. No lo puede ser porque su elemento padre <html> no lo hace tampoco. Irónicamente, este comportamiento aparentemente extraño, nos permite que la altura del contenedor sea siempre la de su columna mayor que va forzando su tamaño y a su vez él fuerza la del body. Sin embargo por alguna razón las columnas como elemento de bloque no heredan bien el alto de su contenedor. Tendremos que aplicarles pues también a ellas el atributo display:table.
    Hasta aquí tendríamos la solución perfecta para Firefox.  Para que WebKit y Presto reaccionen <html> y <body> no tienen un height: 100% y aún así al superar el contenido la altura de la ventana la magia se rompe. IE directamente no comprende los estándares display:table ni el valor inherit. Pero para él aún hay alguna posibilidad.

    <div style="display: table; width: 402px; height: 100%; padding: 2px 0 2px 2px">
      <div style="float: left; width: 250px; height: inherit; background-color: #666;">Columna 1</div>
      <div style="display: table; float: left; width: 150px; height: inherit; background-color: #999;">Columna 2</div>
    </div> 

    Probrar solución para FF y cia. en directo

    crossbrowsing último paso

    crossbrowsing último paso

  4. Corregimos para IE. En el ejercicio aplicamos los CSS sobre los elementos, pero para que la solución nos sirva en la práctica para varios navegadores tendremos que aplicar las excepciones para IE mediante un comentario condicional.
    <div style="display: table; padding: 2px 0px 2px 2px; width: 402px; height: 100%; background-color: #333333;">
      <div style="display: table; float: left; width: 250px; background-color: #999999; height: 100%;">columna 1</div>
      <div style="display: table; float: left; background-color: #ff9900; width: 150px; height: 100%;">Columna2</div>
    </div> 

    Probrar solución para IE en directo
    Este es el código insertado dentro de otros elementos que limitan su altura.

    Titulo columna 1Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam sit amet orci nec enim malesuada sollicitudin. Fusce mattis velit a diam. Nunc interdum.Lorem ipsum dolor sit amet, consectetur adipiscing elit.
    Titulo columna 2Morbi auctor. In mi neque, volutpat quis, rutrum at, vehicula et, felis.

Solución mediante la replica de una tabla

Para los puristas de los estándares y detractores de IE la solución perfecta para montar una estructura de columnas sin tablas y mediante un método consistente y sencillo.

  1. Aplicamos al elemento contenedor el atributo display:table
  2. Añadimos un elemento extra con un display: table-row para dar estabilidad*
  3. A cada columna le ponemos un display: table-cell
  4. Dimensionamos por CSS el contenedor y las columnas.

Sí, ya está, no hay más. Aquí tenéis un ejemplo del método embebido y un link al método como contenedor principal.

<div style="border: 1px solid #333333; display: table; width: 400px;">
  <div style="display:table-row">
    <div style="display: table-cell; width: 250px; background-color: #999999;">Columna 1</div>
    <div style="display: table-cell; width:150px background-color: #ff9900;">Columna 2</div>
  </div>
</div>
Titulo columna 1 Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam sit amet orci nec enim malesuada sollicitudin. Fusce mattis velit a diam. Nunc interdum.
Titulo columna 2 Morbi auctor. In mi neque, volutpat quis, rutrum at, vehicula et, felis.

Puesto que IE no entiende de herencias, obviamente esta es una solución exclusiva para motores de renderizado de verdad. Pero siempre podemos recurrir a la primer solución y aplicarla mediante un comentario condicional.

*Este elemento en principio no es necesario, pero resuelve el problema de firefox con las cargas lentas

Escribe un comentario

Comentario

  1. Absolutamente de acuerdo Samuel, tu recomendación para David es totalmente acertada. Los floats fueron creados para flotar bloques de texto al rededor de imágenes. Hay que tener mucho cuidado cuando los usamos para otros fines. En la mayoría de las ocasiones es mejor usar display: inline o display: inline-block, aunque este no es bien interpretado al 100% por IE a menos que previamente fuese un elemento de linea.
    El problema que plantea David debe radicar probablemente en el mal uso de esas dos propiedades CSS como bien dices.

  2. oye muchas gracias, me resolviste una duda, tengo una maqueta header , 3 columnas y footer, y es el mejor metodo que he encontrado para estirar las columnas hacia el borde inferior., gracias por compartirlo.

    David, trata de utilizar lo menos posibles los float, y las pocisiones absolutas, te libraras de muchos dolores de cabeza.

  3. Hola David, gracias por tu comentario.

    Hasta ahora no me he encontrado con el problema que me comentas, es un formato que llevo ya un tiempo usando con floats en los contenidos tanto de una como de otra columna y como tú bien dices no tendría mucho sentido embeber divs a modo de una gran cebolla 😉
    De hecho tuve que luchar contra mi ser para aceptar que no había más remedio que usar un DIV con display:table-row para estabilizarlo en FF.

    Te propongo que me remitas tu código o la URL donde lo tienes alojado y así poder echarle un vistazo.

    Seguro que tiene solución.

  4. La solución más «purista» y rápida de montar al menos a mi parecer, la que mencionas como «replica de una tabla» puede resultar problemática, o al menos aún no le he encontrado solución efectiva.

    El problema residiría si una vez dentro de la primera columna (por ejemplo) usamos otros div con la propiedad float. El contenido de la segunda columna descuadra en altura (hasta la altura de la capa o capas con la propiedad float)

    Una de las formas que veo para solucionar esto es volver a usar internamente el «modelo de tabla» (table, table-row y table-cell), para seguir maquetando, lo cual, creo que no es lo más correcto, porque puede que ya no te interese que ambas capas tengan la misma altura.

    No se si con alguna propiedad se puede evitar el efecto.

Webmenciones

  • Columnas HTML con CSS Columns - Columnas responsive octubre 2, 2009

    […] cerca del primero creo que ya se ha escrito mucho desde que publiqué Columnas CSS en 2009, pero por entonces era un tema en auge ya que la compatibilidad de los navegadores con los […]

  • css float octubre 2, 2009

    […] Display: table-cell. Puede usarse junto con table y table-row para por ejemplo crear una estructura de varias columnas de la misma altura indistintamente del contenido. Encaja muy bien con los elementos que se suelen utilizar: contenedor, que sería display: table, cabecera, cuerpo y pie, que serían display: table-row, y finalmente las columnas dentro del cuerpo, que utilizarían display: table-cell. Podéis ver el uso de este método en el artículo columnas css […]