Flexbox es la palabreja con la que se denomina al flexible box layout, que podríamos traducir como maquetación de cajas flexibles. ¿Y qué se esconde tras esto? Ni más ni menos que una nueva forma de maquetar interfaces mediantes CSS3.

De acuerdo a la documentación de la MDN, existen 6 diferentes modos de maquetación en CSS. Vamos a dar un repaso a todos ellos:

  • Maquetación de bloques. Es la que todos conocemos; cada elemento es un bloque que, de manera predeterminada, ocupa todo el ancho disponible. Además, los bloques tienen la habilidad de poder flotar. Igualmente podemos organizar el contenido por columnas. Propiedad display: block.
  • Maquetación en línea. Corresponde al modo en que se organizan y comportan los elementos de tipo texto. Propiedad display: inline.
  • Maquetación de tablas. Para el diseño de tablas. Antiguamente se maquetaban páginas web utilizando este modo. Contiene un gran número de modos de display: table, table-cell, table-column, table-row, inline-table, entre otros.
  • Maquetación posicionada. Para cuando la posición de un elemento no guarda (mucha) relación con los demás. Funciona cuando utilizamos la propiedad CSS position con algún valor de estos: fixed, absolute, center o page.
  • Maquetación flexbox. Nos permite diseñar páginas complejas que se redimensionan con elegancia.
  • Maquetación en rejilla, para colocar los elementos relativos a una rejilla.

¿No te ha quedado nada claro lo que es Flexbox? No te preocupes. Vamos a verlo denidamente.

Para comprobarlo, necesitarás tener Google Chrome u Opera actualizado. En la fecha en la que escribo este post tan solo Opera y Chrome lo soportan, pero pronto lo veremos en otros navegadores. Firefox lo soporta parcialmente. Para habilitarlo, debes accedes a la pantalla de configuración (about:config), y cambiar la propiedad layout.css.flexbox.enabled a true. Respecto a Safari y a IE10, soportan una versión antigua diferente de la final. Es de esperar que pronto lo implementen.

Con Flexbox lo que hacemos es que cada elemento tenga un ancho y/o alto que se ajuste dinámicamente al espacio disponible, y si fuera necesario, se apilara sobre otro elemento. A diferencia de la maquetación de bloques, que funciona con una disposición vertical (de arriba a abajo), o la maquetación en línea, con disposición horizontal (izquierda a derecha), Flexbox es completamente independiente de todo esto. Esto es especialmente útil a la hora de diseñar aplicaciones web.

Ejemplo flexbox a fondo

Por lo pronto, echa un vistazo al siguiente ejemplo. Recuerda que debes visitarlo con Google Chrome o con Opera. Pulsa sobre el botón ‘+’ para ver y editar el código fuente. De primeras no se ve nada extraño, ¿verdad? Una página con su cabecera, su pie, y entre medias 3 columnas, siendo la central la principal.

Ejemplo 1 de uso de Flexbox

Echa un vistazo a su código HTML:

<!DOCTYPE html>
<html lang="en">
  <head></head>
  <body>
    <header>header</header>
    <div id='main'>
      <article>article</article>
      <nav>nav</nav>
      <aside>aside</aside>
    </div>
    <footer>footer</footer>
  </body>
</html>

¿Sigues sin ver nada? Fíjate en el orden de los elementos que hay dentro del <div>. En primer lugar se encuentra <article>, y sin embargo este se muestra en segundo lugar, entre <nav> y <aside>. Esto es gracias a la propiedad order disponible en Flexbox. Otro detalle curioso es que las tres columnas tienen exactamente el mismo alto (y no está preestablecido este valor con la propiedad height ni con nada parecido). Por último, si cambiamos el tamaño de la ventana, veremos que la maquetación cambia. Y no solo eso, sino que ahora <article> vuelve a estar en primer lugar.

Este es el código CSS del ejemplo:

header, footer {
   min-height: 100px;
   background: #ffeebb;
}

#main {
   display: flex;
   flex-flow: row;
   min-height: 800px;
}

#main > article {
   background: #dddd88;
   order: 2;
   flex: 3;
}

#main > nav {
   background: #ccccff;
   flex: 1;
   order: 1;
}

#main > aside {
   background: #ccccff;
   flex: 1;
   order: 3;
}

@media all and (max-width: 640px) {   
   #main {
      flex-flow: column;
   }

   #main > article, #main > nav, #main > aside {
      order: 0;
   }

   #main > nav, #main > aside, header, footer {
      min-height: 50px;
      max-height: 50px;
   }
}

Vamos a revisarlo punto por punto:

  1. header, footer – En primer lugar establecemos el diseño de <header> y <footer>. Sencillo: Indicamos que deben tener 100 píxeles de alto, y color beige de fondo.
  2. #main – Se trata del <div> que contiene los otros tres elementos: <article>, <nav> y <aside>. En primer lugar, mediante “display: flex”, establecemos que será un contenedor flex. En segundo lugar indicamos cómo se expanden los elementos del contenedor flex, utilizando la propiedad propiedad atajo fex-flow. Por último, indicamos un alto mínimo de 800 píxels para este contenedor.
  3. #main > article – Ahora definiremos cómo se maqueta el elemento <article>. En primer lugar establecemos su color de fondo. A continuación, indicamos que se mostrará en segunda posición (mediante la propiedad order). Por último, utilizamos la propiedad atajo ‘flex’ para definir su comportamiento flexible: Tan solo indicamos un factor de crecimiento 3 (ahora veremos en qué consiste eso).
  4. #main > nav – Es equivalente al caso anterior, salvo que indicamos un factor de crecimiento de 1.
  5. #main > aside – Al igual que el anterior, se trata de otro elemento flex con un factor de crecimiento 1.
  6. Finalmente, indicamos cómo se comporta el diseño para resoluciones inferiores a 640px:
    1. #main – Ahora los elementos del contenedor flex fluirán en columnas (de arriba a abajo).
    2. Establecemos como ‘order’ 0 a todos los subelementos de #main. Esto indica que se restablece la ordenación secuencial.
    3. Finalmente indicamos a <header>, <footer>, <nav> y <aside> un alto máximo de 50px.

Nos queda indicar qué es eso del factor de crecimiento: Cuando sobra espacio libre entre elementos flex, podemos indicar de qué manera se distribuirá este espacio. Lo podemos hacer mediante un factor de crecimiento flex. Este factor indica el tamaño relativo de un elemento respecto a otros. Por ejemplo. Supongamos 3 ítems. A cada uno le establecemos un factor de crecimiento flex diferente:

  • #Item 1 – Factor de crecimiento 1.
  • #Item 2 – Factor de crecimiento 2. Este elemento ocupará el doble de espacio que #Item 1.
  • #Item 3 – Factor de crecimiento 5. Este elemento ocupará 5 veces más espacio que #Item 1.

Es decir, nos permite controlar el tamaño de los elementos de un layout flexbox.

Propiedades flexbox

display

Si bien no se trata de una propiedad flexbox, como ya hemos visto en el ejemplo, es la que define cómo establecer un nuevo contenedor flex. Para ello, podemos escoger dos valores:

  • flex – Se trata de un contenedor flex a nivel de bloque.
  • inline-flex – Crearíamos un contenedor flex a nivel de línea.

flex-direction

Establece la dirección que seguirán los elementos de un contenedor flex. A esta dirección también se la conoce como eje principal (main axis). Se establece en el contenedor flex. Admite los siguientes valores:

  • row – Se ordenan en filas (horizontalmente). Es el valor predeterminado.
  • row-reverse – Se ordenan en filas (horizontalmente) pero en sentido inverso al anterior.
  • column – Se ordenan en columnas (verticalmente).
  • column-reverse – Se ordenan en columnas (verticalmente) pero en sentido inverso al anterior.

flex-wrap

Indica si el contenedor es o no “multilínea”. Es decir, el comportamiento que tiene este cuando los elementos exceden el tamaño. ¿Qué ocurre a partir de ahí? ¿Se ocultan o se muestran en “otra línea”? Estas nuevas líneas, ¿cómo se ordenaran? Este nuevo eje (perpendicular al eje principal) se le conoce como eje cruzado (cross axis). Se establece en el contenedor flex. Valores posibles:

  • nowrap. Es de una sola línea. Es el valor predeterminado.
  • wrap. Es multilínea.
  • wrap-reverse. Es multilínea en sentido inverso.

flex-flow

Ya hemos utilizado esta propiedad en el ejemplo anterior, que se establece en el contenedor flex. Es un atajo para asignar a la vez flex-direction y flex-wrap. Es decir, los siguientes serían valores válidos:

Ejemplo 1

Ordenar en horizontalmente, en una sola línea, y en el sentido predeterminado (de izquierda a derecha)

flex-flow: row;

Diagrama de ejemplo del comportamiento de la propiedad Flex flex-flow

Ejemplo 2

Ordenar verticalmente, en modo “multicolumna”, en los sentidos predeterminados (de arriba a abajo, y de izquierda a derecha)

flex-flow: column wrap;

Diagrama de ejemplo del comportamiento de la propiedad Flex flex-flow

Ejemplo 3

Ordenar horizontalmente en sentido inverso (derecha a izquierda), y en modo multilínea con sentido también inverso (de abajo a arriba).

flex-flow: row-reverse wrap-reverse;

Diagrama de ejemplo del comportamiento de la propiedad Flex flex-flow

Nota: Las direcciones predeterminadas dependen del modo de escritura del navegador. En español o inglés el modo estándar es horizontal de izquierda a derecha. En otros idiomas esto varía, y por tanto podría variar la maquetación que realices.

order

También hemos presentado ya esta propiedad, que solo tiene efecto en los elementos flex. De manera predeterminada todos los elementos tendrán como valor order 0. Esta propiedad indica la posición en que se mostrará un elemento, mostrando siempre en primer lugar los que menor valor tengan.

Ten en cuenta que este valor order no tiene efecto en cómo se muestra la pantalla, por ejemplo, en lectores de pantalla para usuarios invidentes. Es decir, modifica la ordenación estética, pero no la lógica.

flex-grow

Establece el factor de crecimiento flex. Como hemos visto, este factor, que se asigna sobre elementos flex, indica cuánto crecerá este elemento en relación a los demás cuando haya espacio libre positivo.

flex-shrink

Establece el factor de encogimiento flex. Se asigna sobre elementos flex, e indica cuánto decrecerá un elemento respecto a los demás cuando no haya espacio libre positivo.

flex-basis

Estblece el ancho base inicial del elemento flex. Acepta los mismos valores que la propiedad ‘width’, y su funcionamiento es similar, salvo en caso de asignar el valor ‘auto’. Ten en cuenta que establece el valor inicial (algo similar a un ancho mínimo). Estos son los valores posibles:

  • Porcentaje – Se indica el ancho en porcentaje respecto al tamaño del contenedor padre.
  • Valor absoluto – Se establece el ancho mediante unidades absolutas, como pueda ser px, em o pt.
  • auto – El ancho se calcula en función del contenido de cada ítem.

El siguiente diagrama quizás te aclare mejor estos conceptos:

Diagrama del comportamiento de la propiedad Flex flex-basis

Tenemos 3 elementos, con unos factores de crecimiento flex de 1, 1 y 2 respectivamente. Veamos qué ocurre en cada ejemplo:

  1. En el primer caso establecemos un ancho base flex de 0. Por supuesto los tres elementos exceden ese tamaño. Todo el espacio se reparte para los 3 elementos en función de su factor flex.
  2. En el segundo caso establecemos un ancho base flex ‘auto’. Esto es, el ancho de cada elemento dependerá de su contenido: A cada ítem se le añade un espacio extra, que se calculará en función del factor de crecimiento flex.

flex

Esta propiedad, que se aplica a nivel de elementos flex, establece a la vez flex-grow, flex-shrink y flex-basis. Los valores predeterminados son ’0 1 auto’, es decir, un factor de crecimiento de 0, un factor de encogimiento de 1, y un ancho base automático.

Admite también el valor ‘none’, que se computa como ‘o o auto’.

justify-content

Supón que tienes varios ítems flex en diferentes líneas. Todos ellos han alcanzado su tamaño máximo, y a pesar de ello no rellenan todo el espacio disponible. ¿Cómo los podemos alinear? Mediante la propiedad justify-content. Estos son los valores que acepta:

  • flex-start – Todos se alinean al comienzo del eje principal.
  • flex-end – Todos se alinean al final del eje principal.
  • center – Se centran en el eje principal.
  • space-between – Se añaden espacios entre ellos hasta ocupar todo el hueco.
  • space-around – Se añaden espacios alrededor de ellos hasta ocupar todo el hueco.

Diagrama del comportamiento de la propiedad Flex justify-content

align-item y align-self

Ahora supón que cada ítem flex tiene un alto diferente. ¿Cómo los alineamos respecto al eje cruzado? Utilizando la propiedad align-item. La propiedad align-self sirve para sobrescribir el valor predeterminado en un elemento en concreto.

Valores posibles:

  • flex-start – Los elementos se alinean al comienzo del eje cruzado.
  • flex-end – Se alinean al final del eje cruzado.
  • center – Se centran en el eje cruzado.
  • baseline – Se alinean de manera que la línea base de todos ellos coincida.
  • stretch – Iguala los tamaños, en la medida de lo posible, para que todos rellenen el espacio disponible.

Diagrama del comportamiento de la propiedad Flex align-items

align-content

¿Y si tenemos diferentes líneas? ¿Cómo se distribuiría el espacio vacío en el caso de que estas no completaran todo el espacio del contenedor flex? Lo resolvemos mediante la propiedad align-content, que acepta estos valores:

  • flex-start – Todas las líneas se alinean al comienzo del eje cruzado.
  • flex-end – Se alinean al final del eje cruzado.
  • center – Se centran en el eje cruzado.
  • space-between – Se añade un espacio entre cada una de las líneas hasta ocupar todo el tamaño del contenedor.
  • space-around – Se añade un espacio alrededor de cada una de las líneas  hasta ocupar todo el tamaño del contenedor.
  • stretch – Se igualan las alturas de las líneas hasta ocupar todo el espacio disponible.

Diagrama del comportamiento de la propiedad Flex align-content

¡Basta de teoría!

Ya sabemos qué es flexbox, para qué sirve, cómo funciona, y conocemos todas sus propiedades y conceptos. ¡Vamos a jugar un poco con él! Para ello, accede a esta página con Google Chrome: http://bennettfeely.com/flexplorer/. Se trata de una web que te permite explorar cómo se comportaría Flexbox en función de los valores que introduzcas. Además, te genera el código CSS necesario.

Nota: Recuerda que flexbox es un borrador, y por tanto los navegadores añaden prefijos a cada propiedad.

En concreto nos deja establecer las siguientes propiedades:

  • flex – Que como hemos visto es un atajo de flex-grow, flex-shrink y flex-basis.
  • flex-direction.
  • flex-wrap.
  • justify-content.

Igualmente, nos permite asignar el número de ítems que contendrá el contenedor flex.

Ejemplo 1

  • flex: 1 0 auto;
  • flex-direction: row;
  • flex-wrap: wrap;
  • # of flex items: 20

Con esta combinación indicamos que los elementos de nuestra interfaz flexbox se ordenarán en filas con el sentido predeterminado (flex-direction: row), en modo multilínea predeterminado (flex-wrap: wrap). Igualmente, indicamos que deben ocupar todo el espacio libre disponible (el 1 de la propiedad flex) y se repartirá en cada fila de manera relativa (el “padding” de cada ítem de una misma fila es equivalente).

Ejemplo 1 de flex

Ejemplo 2

  • flex: 1 0 auto;
  • flex-direction: row;
  • flex-wrap: wrap;
  • # of flex items: 5

Este ejemplo es equivalente al anterior, salvo que en lugar de tener 20 elementos flex, tan solo tiene 5. Apreciamos claramente que todos tienen el mismo “padding” a la izquierda y a la derecha.

Ejemplo flex 2

Ejemplo 3

  • flex: 1 0 0;
  • flex-direction: row;
  • flex-wrap: wrap;
  • # of flex items: 5

Repetimos los mismos valores que en el Ejemplo 2, pero en esta ocasión sustituimos el valor “auto” de la propiedad “flex” por un 0. Recuerda que este campo corresponde a flex-basis. Al poner un 0, el espacio sobrante se reparte de manera que todos guarden proporción respecto a su factor de crecimiento flex, que en este caso es la misma para todos ellos: 1. Por tanto ahora, a diferencia del Ejemplo 2, todos tienen el mismo tamaño.

Ejemplo flex 3

Ejemplo 4

  • flex: 0 0 auto;
  • flex-direction: row;
  • flex-wrap: wrap;
  • # of flex items: 20
  • justify-content: flex-start;

Modificamos el número de ítems para que haya 20, y ponemos en la propiedad flex los valores “0 0 auto”. Es decir, eliminamos el factor de crecimiento, y añadimos un ancho base automático. Al no haber asignado un factor de crecimiento, los ítems se quedan con su valor predeterminado.

Ejemplo flex 4

Ejemplo 5

  • flex: 0 0 auto;
  • flex-direction: row;
  • flex-wrap: wrap;
  • # of flex items: 20
  • justify-content: space-between;

Equivalente al Ejemplo 4, salvo que modificamos la propiedad justify-content para asignar valor “space-between”, que en cada fila reparte el espacio disponible de manera equivalente entre todos los ítems.

Ejemplo flex 5

Puedes probar a establecer otros valores en justify-content para comprobar cómo se comporta.

Recursos

La especificación de flexbox ha sufrido muchas modificaciones en los últimos tres años. De hecho IE y Safari soportan versiones antiguas. En este artículo el siempre genial Chris Coyer arroja un poco de luz sobre la evolución de flexbox.

En cualquiera caso, la mejor referencia (como siempre) es la propia documentación del w3c del Módulo de Maquetación CSS de Cajas Flexibles.

Aquí tienes un buen tutorial que te introduce paso a paso en Flexbox.

Como campo de pruebas, además de tu propio editor/navegador, puedes utilizar Flexplorer o CSS Flexbox Please!

No dejes de revisar la documentación de la MDN sobre flexbox.