La disposición en grid (rejilla) es hoy más utilizada que nunca por su fácil adaptación al diseño responsive. El llamado masonry layout, también conocido como “estilo Pinterest” por que lo popularizó esta red social o como grid layout en cascada, es una versión del grid que se adapta a elementos con distinta altura. Hasta ahora la técnica más utilizada para conseguir el masonry layout era con javascript, por ejemplo el plugin mansory para jQuery.

En este tutorial vamos a indagar en la propiedad CSS column-count y algunas relacionadas para conseguir un grid masonry sin una sola línea de javascript, CSS puro.

Introducción a column-count

La propiedad column-count se utiliza definiendo el número de columnas en el que queremos dividir el contenido de un determinado elemento. Por ejemplo, podemos dividir el texto de un div en cuatro columnas:

<style>
.column-4 {
    column-count: 4;
}
</style>
<div class="column-4">
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua....
</div>

En lugar de un número de columnas concretas, también podemos especificar el valor auto si se utiliza junto con la propiedad column-width. El contenido se dividirá automáticamente en el número de columnas más cercano para completar todo el ancho disponible. Por ejemplo, con un column-count: auto y column-width: 50%, el contenido se distribuirá en dos columnas.

Compatibilidad entre navegadores

column-count es soportado en todas las versiones de Edge y en IE desde la versión 10:

  • Firefox, desde la versión 2.0, soporta la alternativa -moz-column-count
  • Safari, desde 3.1, y Chrome, desde 4.0, soportan la alternativa -webkit-column-count
  • Las últimas versiones de Firefox, Safari y Chrome soportan column-count sin problemas, para aumentar la compatibilidad con versiones más antiguas se recomienda añadir -moz-column-count y -webkit-column-count. Más info en canisue: multicolumn.

Creando un layout masonry con column-count

Vamos al lío. Como ejemplo, vamos a crear un layout masonry para un hipotético blog. Supongamos el siguiente marcado para un página típica del índice de posts:

<header class="header">
    <h1>Mi Blog</h1>
</header>
<main class="blog masonry">
    <p class="span-all-columns">Elemento para demostrar el uso de column-span. No funciona en Firefox.</p>
    <article class="post">
        <img src="https://farm9.staticflickr.com/8083/8354311074_beafb69758_z.jpg">
        <h2>Lorem ipsum</h2>
        <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit.</p>
    </article>
    <article class="post">
        <p>Neque, vitae, fugiat, libero corrupti officiis sint facilis tempora quidem repudiandae praesentium odit similique adipisci aut.</p>
    </article>
    <article class="post">
        <blockquote class="twitter-tweet" lang="es"><p>Utilizar valores por defecto en el Option API de <a href="https://twitter.com/hashtag/Wordpress?src=hash">#Wordpress</a> de la forma correcta → <a href="http://t.co/btEE3AUIZa">http://t.co/btEE3AUIZa</a></p>&mdash; Juan Padial (@CybMeta) <a href="https://twitter.com/CybMeta/statuses/489457002444509184">julio 16, 2014</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
    </article>
    <article class="post">
        <img src="https://farm5.staticflickr.com/4012/4605804857_40fb134042_z.jpg">
        <h2>Maravilloso paisaje de montaña</h2>
    </article>
    <article class="post">
        <h2>Otro post</h2>
    </article>
    <article class="post">
      <img src="https://farm5.staticflickr.com/4052/4543929183_58d0651c14_z.jpg">
    </article>
    <article class="post">
        <h2>Fatima Al Qadiri - Hydra</h2>
        <iframe width="420" height="315" src="//www.youtube.com/embed/QFiwYdalaEg" frameborder="0" allowfullscreen></iframe>
    </article>
    <article class="post">Ab, adipisci, temporibus eaque quis harum perferendis incidunt cupiditate doloribus dolor numquam voluptates ipsum dolore aspernatur et voluptate ipsam beatae animi culpa.
    </article>
</main>

Si no aplicamos ningún CSS, cada post aparecerá uno bajo otro:

1 Columna - no masonry
1 Columna – no masonry

Hacer que aparezcan en columnas es tan fácil como:

  1. Definir el número de columnas que queremos con column-count en el elemento padre
  2. Cada elemento hijo (en este caso <article>) ha de comportarse como un elemento inline-block, no vale block ni inline. Hay que aplicarle la propiedad display: inline-block. Esto se debe a que es necesario que el propio elemento sea formateado a nivel inline pero que el contenido sea formateado a nivel bloque, de lo contrario el contenido del elemento puede dividirse comenzando en una columna y continuando en la siguiente.
.masonry {
    column-count: 4;
    -moz-column-count: 4;
    -webkit-column-count: 4;
}
.masonry .post {
    display: inline-block;
}

Ahora ya tenemos las 4 columnas, aunque se superpone el contenido de algunos elementos, como imágenes, los iframes de youtube, etc:

masonry-1
El contenido de algunos elementos se superpone

Tendremos entonces que solucionar esto con más reglas CSS:

  • A cada elemento <article> le damos una anchura igual al 100% de la columna
  • A los elementos img, iframe y demás que necesitemos que no superen la anchura de su contenedor le damos un max-width del 100% y display: block.
  • Podemos utilizar la regla column-gap para establecer un espacio entre cada columna, por ejemplo 20px.
  • Al elemento <p> de clase span-all-columns le aplicamos la propiedad column-span: all. Es a modo de ejemplo para ver como este párrafo es excluido de las columnas y ocupa el ancho completo. Esta propiedad CSS no es soportada por Firefox ni ofrece alternativa.
  • Añadios también un poco de margen, padding y un borde para distinguir mejor cada post. También introduzco la propiedad word-wrap para evitar que palabras largas en los títulos puedan estropear las columnas.

El CSS ahora queda:

.masonry {
    column-count: 4;
    -moz-column-count: 4;
    -webkit-column-count: 4;
    column-gap: 20px;
    -moz-column-gap: 20px;
    -webkit-column-gap: 20px;
}
.masonry .post {
    display: inline-block;
    width: 100%;
    margin-bottom: 20px;
    padding: 20px;
    border: 1px solid #000;
}
.masonry .post img,
.masonry .post iframe,
.masonry .post blockquote {
    max-width: 100%;
    display: block;    
}
.span-all-columns {
    column-span: all;
    -webkit-column-span: all;
    -mox-column-span: all;
}
.masonry h1, .masonry h2 {
    -ms-word-wrap: break-word;
    word-wrap: break-word;
}

Y el resultado es un layout masonry totalmente funcional:

Masonry total con CSS
El layout masonry ya es completo y funcional

Hacerlo responsive

La propiedad column-count es en sí misma responsive. Con el código utilizado anteriormente, el contenido se dividirá en 4 columnas sea cual sea el tamaño de pantalla. Y como a cada elemento le hemos dado un max-width del 100%, se adaptará a la anchura de cada columna cuándo esta cambie. Pero claro, tener el contenido dividido en cuatro columnas en la pantalla de un móvil no es nada apropiado para este ejemplo.

Con tan sólo cambiar el número de columnas que queremos según el ancho de la pantalla tendremos el layout masonry con un aspecto óptimo en todos los dispositivos. Puedes ir probando hasta encontrar cuál es el número de columnas idóneo en cada caso. Para este ejemplo he elegido mostrar una sola columna hasta pantallas de 768 px (pantallas muy pequeñas), 2 columnas por encima de 768 px (pantallas pequeñas), 2 columnas por encima de 992 px (pantallas medianas) y 4 columnas por encima de 1200 px (grandes pantallas):

.masonry {
    column-count: 1;
    -moz-column-count: 1;
    -webkit-column-count: 1;
    column-gap: 20px;
    -moz-column-gap: 20px;
    -webkit-column-gap: 20px
}
.masonry .post {
    display: inline-block;
    width: 100%;
    margin-bottom: 20px;
    padding: 20px;
    border: 1px solid #000;
}
.masonry .post img,
.masonry .post iframe,
.masonry .post blockquote {
    max-width: 100%;
    display: block;    
}
.span-all-columns {
    column-span: all;
    -webkit-column-span: all;
    -mox-column-span: all;
}
.masonry h1, .masonry h2 {
    -ms-word-wrap: break-word;
    word-wrap: break-word;
}
@media (min-width: 768px) {
    .masonry {
        column-count: 2;
        -moz-column-count: 2;
        -webkit-column-count: 2;
    }
}
@media (min-width: 992px) {
    .masonry {
        column-count: 3;
        -moz-column-count: 3;
        -webkit-column-count: 3;
    }
}
@media (min-width: 1200px) {
    .masonry {
        column-count: 4;
        -moz-column-count: 4;
        -webkit-column-count: 4;
    }
}

Ya tenemos completamente listo una disposición de las entradas del supuesto blog en formato masonry, adaptado a diferentes dispositivos y sin escribir una sóla línea de JavaSript, todo CSS y la magia de column-count. Mira el demo, cambia el tamaño de pantalla y juega con él todo lo que quieras.

Demo