Logo de Mosaic
Temas de CSS
Flexbox: ¿vía rápida hacia el nirvana del layout?

Flexbox: ¿vía rápida hacia el nirvana del layout?

Chris David Mills. 9 de octubre de 2012. Artículo original en inglés

Introducción

HTML y CSS constituyen un mecanismo de distribución de contenidos genial en muchos aspectos — es fácil de aprender, flexible y potente. Pero un aspecto en el que nunca se ha destacado es en el de los diseños complejos. Si desea crear un diseño tipográfico simple con una imagen flotante o dos, entonces está bien, pero la producción de complicados diseños de varias columnas ha sido siempre más incómodo y cuestión de 'hacks', y frustrante para conseguir que funcione de forma consistente y precisa sobre los distintos navegadores. Por lo general, se tienden a abusar de floats y otras construcciones para este fin, y los errores y las diferencias de renderizado pueden arruinarte la diversión.

Para combatir esto, CSS3 incluye una serie de módulos que existen para hacer diferentes tareas de diseño mucho más fáciles. Ya consideramos Multi-column layout y Generated Content for Paged Media en otros artículos, y ahora volvemos nuestra atención al Módulo de Layout de Cajas Flexibles.

Flexbox, como se le llama comúnmente, está diseñado para permitirnos manipular fácilmente el diseño de una serie de elementos hijo en formas que anteriormente eran difíciles. Por ejemplo:

Suena bastante útil, ¿no? Explorémoslo con más detalle.

Nota

En este artículo se utiliza la última sintaxis Flexbox, actualmente soportada en Opera Mobile 12.1+, Opera 12.5+, Firefox 18+ (parcialmente) y Chrome. Chrome necesita prefijos -webkit-, mientras que Opera ofrece soporte sin prefijos desde el principio. Firefox ofrece soporte parcial con un prefijo -moz-, y el soporte también se oculta detrás de una opción de configuración (para activarlo, ir a about:config en la barra de direcciones, buscra "FlexBox" y hacer doble clic en layout.css.flexbox de forma que su valor quede como true). Nótese que otros navegadores ofrecen Flexbox desde 2009, pero utilizando una sintaxis antigua, obsoleta que no debe utilizarse. Hay que tener esto en cuenta a la hora de leer y usar el código de artículos anteriores a 2012 sobre Flexbox - Chris Coyier tiene más información sobre cómo saber si estás leyendo un artículo obsoleto.

Un ejemplo simple de flex

Para comenzar la fiesta flex, vamos a considerar un ejemplo sencillo para mostrar lo fácil que es el diseño con Flexbox. Consideraremos una construcción de tipo "fat footer" con tres elementos hijos, cada uno de los cuales contiene contenido típico de un pie de página. Tendremos datos de contacto, enlaces importantes y el aviso de derechos de autor. Queremos mostrar esa información horizontalmente repartida por el pie de página, centrada verticalmente, y queremos que los enlaces tengan el doble de ancho que los otros dos hijos. Actualmente normalmente se haría esto flotando los elementos secundarios, dándoles un ancho y ajustando la alineación usando cantidades variables de relleno, etc. Esto es a menudo incómodo e impreciso si no se establecen valores fijos para todas las dimensiones, algo que puede hacer las cosas bastante inflexible. Pero Flexbox puede ayudar.

Un diseño simple de una sola columna con un 'fat footer', que contiene tres contenedores secundarios dispuestos horizontalmente

Figura 1: Mi ejemplo flexible. Todo es bastante simple, aparte del pie de página, que tiene un diseño flexible que consta de tres cajas.

Nota:

Puedes ver el ejemplo completo (Figura 1) — verás que he hecho un pequeño diseño moderno con una columna de contenido y un pie de página en la parte inferior, que se mantiene en su lugar por medio de un poco de magia position: fixed;. La disposición es flexible, con el tamaño de la columna de la página principal como porcentaje de la anchura de la página, y los elementos secundarios del pie de página cambian de tamaño en proporción a la columna principal. También te darás cuenta que he utilizado unas cuantas media queries para cambiar el diseño para anchos de pantalla más pequeños.

Primeros pasos con Flexbox

Así que, ¿cómo empezamos con Flexbox? La mayoría de las propiedades FlexBox se aplican al contenedor principal de los elementos a los que deseas aplicar un layout. Para especificar que deseas disponer un contenedor como Flexbox, se utiliza un valor especial de la propiedad display, de esta forma:

footer {
  display: flex;
}

A continuación, puedes utilizar la propiedad flex-flow para especificar que deseas que sus elementos hijos estén dispuestos en una row (es el valor por defecto), o una column. También puedes incluir la palabra clave wrap, para especificar que deseas que el contenido salte a una nueva línea si el contenedor primario es demasiado estrecho para que todos los hijos FlexBox quepan en una línea. En mi ejemplo, he puesto los hijos del pie de página a row wrap:

footer {
  display: flex;
  flex-flow: row wrap;
}

El significado de la palabra clave wrap quedará claro más adelante.

Nota

flex-flow es en realidad una propiedad abreviada, para las dos propiedades flex-direction (con valores row, column, row-reverse o column-reverse; los dos últimos valores que la fila o columna corra en la dirección opuesta) y flex-wrap (con valores, wrap, no-wrap o wrap-reverse).

Eje principal, eje transversal

Un concepto al que acostumbrarse cuando se trabaja con Flexbox es el de eje principal y eje transversal, que funcionan un poco como los ejes X e Y, pero con diferencias. El eje principal siempre va en la dirección del flujo de flex, horizontalmente si los hijos flex se colocan en fila y vertical si se colocan en columna. El eje transversal es perpendicular al eje principal. Estos se ilustran en la Figura 2.

Una ilustración del eje principal y eje transversal de un Flexbox: el eje principal siempre corre en la dirección de la fila o columna, y el eje transversal es perpendicular al principal

Figura 2: Una ilustración del eje principal y el eje transversal de una Flexbox.

Ajustar la alineación de los hijos FlexBox

Flexbox cuenta con un número de maneras de ayudar a alinear los hijos a lo largo del eje principal y transversal.

align-items sobre el eje transversal

El primero que veremos es align-items, que permite alinear los hijos FlexBox lo largo del eje transversal. Los diferentes valores son:

Todos se explican por sí mismos. Para verlos en acción, ve a jugar con la demo, y ajusta los valores, o echa un vistazo a la Figura 3. Para el ejemplo, acabé optando por:

footer {
  display: flex;
  flex-flow: row wrap;
  align-items: stretch;
}

Y ahí está — todos los ítems ocuparán toda la altura de su contenedor padre, sin importar lo que cambie la anchura y la altura por cambios de tamaño de la ventana. Es simplemente increíble: ¿Cuántas veces en el pasado has querido dar a un conjunto de columnas la misma altura aunque contienen una cantidad diferente de contenido, y tuviste que perder el tiempo con soluciones inflexibles como establecer una altura igual para todos ellos, o usar columnas falsas?

Muestra de cómo los distintos valores de alineación de elementos afectan a los contenedores hijos: su alineación vertical es diferente

Figura 3: Mostrando cómo los distintos valores de alineación de elementos afectan contenedores secundarios. De arriba a abajo: flex-start, center, flex-end y stretch.

Nota

También hay una propiedad llamada align-self, que permite definir el comportamiento align-item para cada hijo flex particular. Estos se imponen sobre align-items.

justify-content sobre el eje principal

La otra propiedad principal de esta categoría que se utiliza mucho es justify-content, que especifica cómo se disponen los elementos sobre el eje principal, en términos de lo que sucede con el espacio blanco sobrante entre los hijos. Esta propiedad no tiene ningún efecto cuando se ha establecido que hijos y márgenes ocupen todo el espacio disponible sobre el eje principal, como es el caso de mi ejemplo principal. Por lo tanto, he creado otro ejemplo para demostrar el uso de justify-content: por favor, echa un vistazo al ejemplo Flexbox de ancho fijo.

En este ejemplo he hecho que los hijos FlexBox ocupen un porcentaje dado de la anchura del eje principal:

#first {
  width: 25%;
}
    
#second {
  width: 40%;
}
     
 #third {
  width: 25%;
}

Luego, en el contenedor padre he dado un valor de justify-content de la siguiente manera:

footer {
  display: flex;
  flex-flow: row wrap;
  align-items: stretch;
  justify-content: space-around;
}

Este valor funciona bastante bien: repartir todo el espacio entre los elementos hijos y en el exterior de todos ellos en cantidades iguales. Los otros valores disponibles son los siguientes:

La Figura 4 muestra el efecto de los diferentes ajustes de justify-content:

Muestra de cómo los distintos valores de justify-content afectan a los contenedores hijos: su posición horizontal se ve afectada

Figura 4: Muestra de cómo los distintos valores de justify-content afectan a los contenedores hijos. De arriba a abajo - flex-start, center, flex-end y space-around.

align-content para alinear Flexboxes multilínea

También se puede especificar cómo se distribuirá el espacio sobrante entre múltiples líneas de hijos Flexbox, en el caso Flexboxes de varias líneas, es decir, cuando se ha usado la palabra wrap. De hecho, sólo tiene efecto cuando los hijos Flexbox ocupan una cantidad fija de espacio en la dirección del eje transversal, o una altura fija en el caso de filas. Los valores disponibles son:

Alterar el orden de disposición de elementos

Tradicionalmente ha sido doloroso cambiar el orden en que los elementos se visualizan sin jugar un poco con el orden del código fuente. No con Flexbox. Flexbox permite establecer la propiedad order a los elementos hijos para indicar el orden en que aparecerán en la fila o columna Flexbox. Esta propiedad toma un valor entero — llamado grupo ordinal— y cuanto mayor sea el grupo ordinal, más tarde aparecerá el hijo. Así, por ejemplo, volviendo a mi ejemplo de fat footer flexible, la caja de enlaces es el segundo elemento hijo por defecto, tal y como se muestra en la figura 5.

El orden predeterminado de los hijos del pie de página en este ejemplo es: contacto, enlaces, derechos de autor

Figura 5: El orden predeterminado de los hijos del pie de página: contacto, enlaces, derechos de autor.

Por defecto, todos los hijos Flexbox están en el grupo ordinal 0. Podemos cambiar fácilmente este orden dando a los hijos diferentes valores de grupo ordinal. Los valores más altos aparecerán antes en la lista de hijos flex: el orden de los hijos con un mismo grupo ordinal siempre se regirá por el orden en el código fuente. Así que en mi ejemplo, he hecho que los enlaces aparezcan al final estableciendo su grupo ordinal a 1 (véase el resultado en la Figura 6):

#second {
  order: 1;
}
El nuevo orden de los hijos del pie de página en este ejemplo es: contacto, derechos de autor, enlaces

Figura 6: La propiedad order nos ha dado un nuevo orden para los hijos del pie de página.

Nota

Pueden usarse valores negativos de order.

Dar flex a los elementos

Probablemente la característica más poderosa de Flexbox es la capacidad de ajustar la longitud de los elementos hijos en la dirección del flujo de flex (width si flex-flow es row o height si flex-flow es column) a una cantidad flexible dependiendo de la cantidad de espacio disponible en el elemento padre en esa dirección. Esto se hace utilizando la propiedad flex, cuyo valor puede tomar un total de tres partes. Añadámoslas una a una y veamos el efecto que tienen. En primer lugar, un "factor de crecimiento flex":

#first {
  flex: 1;
}
    
#second {
  flex: 1;
}
    
#third {
  flex: 1;
}

Son valores sin unidades que sirven como proporción: dictan qué cantidad de espacio disponible en el interior del padres debe tomar cada hijo. Si todos se ponen a 1 a cada hijo se le dará un tamaño igual dentro de la Flexbox. Si se diese a uno de los hijos un valor de 2, ese tendría el doble de espacio que los demás:

#first {
  flex: 1;
}
    
#second {
  flex: 2;
}
    
#third {
  flex: 1;
}

También se puede configurar un ancho preferido para cada hijo, así:

#first {
  flex: 1 200px;
}
    
#second {
  flex: 2 300px;
}
    
#third {
  flex: 1 250px;
}

En primer lugar, las anchuras preferidas se aplican a cada hijo. Después el espacio restante en el interior del elemento padre se divide de acuerdo a los factores de crecimiento flex y se reparte a los hijos para llegar a su anchura final. Así, a los hijos se les darían tamaños a lo largo del eje principal de 200, 300 y 250 píxeles, para un total de 750 píxeles. Si el contenedor primario fuese de 950 píxeles a lo largo del eje principal, entonces habría un espacio adicional de 200 píxeles para distribuir entre los hijos. A los hijos primero y tercero se les daría 50 píxeles, ya que tienen un factor de crecimiento flex de 1. Su tamaño final sería de 250 píxeles y 300 píxeles respectivamente. Al segundo hijo se le darían 100 píxeles, ya que tiene un factor de crecimiento flex de 2. Su tamaño final sería de 400 píxeles.

La tercera parte del valor flex se utiliza muy poco, pero vamos a verla si acaso. También se puede dar a los elementos hijos un "factor de contracción flex", así:

#first {
  flex: 1 1 400px;
}
    
#second {
  flex: 2 3 600px;
}
    
#third {
  flex: 1 2 400px;
}

Los factores de contracción flex, a pesar de su nombre, son valores positivos: los segundos valores sin unidades en las declaraciones anteriores. Estos sólo entran en juego cuando los hijos desbordan su contenedor padre en la dirección del eje principal. También actúan como valores de proporción, pero esta vez especifican la proporción de la "cantidad de desbordamiento" (la cantidad en que los hijos desbordan el contenedor) que se deducirá del tamaño de cada hijo, para que el tamaño total se iguale al tamaño del padre: para detener el desbordamiento, en la práctica.

Pongamos que el contenedor primario es de 1100 píxeles a lo largo del eje principal. Así, los hijos lo desbordarían por 300 píxeles (equivalen a 1400 píxeles a lo largo del eje principal, en total). Debido a los factores de contracción flex que les hemos fijado:

Así que un mayor factor de encogimiento flex en realidad se traduce en un elemento más pequeño.

Los valores con que acabé en mi ejemplo principal son los siguientes:

#first {
  flex: 1 0 7rem;
}
    
#second {
  order: 1;
  flex: 2 0 8rem;
}
    
#third {
  flex: 1.5 0 7rem;
}

Flexbox: ventajas responsive

Una cosa que ha funcionado bastante bien en mi ejemplo es combinaR un Flexbox multilínea (flex-flow: row wrap) con una longitud flex preferida para los elementos hijos (por ejemplo, flex: 1 0 7rem ;), y las media queries. En ventana estrechas, la anchura preferida no puede alcanzarse sin desbordamiento del elemento padre y, por lo tanto, los hijos Flexbox se disponen en líneas múltiples para mantener las cosas con buen aspecto, como se muestra en la Figura 7.

Una aplicación sencilla de Flexbox nos da un diseño responsive útil - la imagen muestra un diseño de una, dos y tres líneas, en diferentes anchos de ventana Segunda imagen del ejemplo, en que el bloque de enlaces salta a una segunda línea al reducirse el ancho de la ventana Tercera imagen. Las tres cajas se muestran en tres filas diferentes en una ventana todavía más estrecha

Figura 7: Una aplicación sencilla de Flexbox nos da un diseño responsive útil.

flex: auto y flex: initial

Flex tiene algunos otros valores útiles, descritos en la parte de la especificación titulada Valores comunes de 'flex'. Dos de los más útiles son auto e initial. Dar flex: auto; a un elemento hijo de una caja flexible (equivalente a flex: 1 1 auto) hará que sea totalmente flexible y le dará tamaño de acuerdo a cualesquiera propiedades width/height o min/max-width/height que se hayan fijado; se expandirá para ocupar una proporción de cualquier espacio libre disponible, pero luego se encogerá para ajustarse a su contenido cuando no haya espacio libre extra. Esto puede tener algunos efectos interesantes cuando se combina con un min-width, por ejemplo. Echa un vistazo a mi ejemplo de Flex auto. En este ejemplo, al contenedor padre se le da flex-flow: row y al tercer contenedor hijo se le da flex: auto; ala vez que tiene un min-width. Por lo tanto, se expande hasta llenar cualquier espacio sobrante en la línea, sin importar si la barra de herramientas es de varias líneas o no, y entonces se encoge cuidadosamente a medida que se hace más pequeño, lo que permite que los botones hijos se reorganizan para adaptarse.

Intenta cambiar el valor de flex: auto; por flex: initial (equivalente a flex: 0 1 auto) y verás que el tercer contenedor hijo deja de aumentar de tamaño cuando hay exceso de espacio, pero aún así se encoge si es necesario.

Toda esta potencia y flexibilidad con tan poco código es definitivamente una buena cosa.

Degradación grácil

Flexbox es un modelo completamente nuevo de diseño, y los navegadores que no lo entienden simplemente lo ignorarán. Esto podría parecer un ultimátum que nos impide usarlo. Sin embargo, no es necesariamente así. Por ejemplo, podrían usarse floats o tablas CSS para el diseño "desktop" del sitio, y optar por utilizar Flexbox para anchos de navegador muy pequeños (móvil), tal vez para despalazar una navegación del lado izquierdo a la parte inferior de la página principal.

Si se da a todos los elementos de la página (navegación, encabezado, pie de página, etc) display: block; por defecto antes de las reglas FlexBox, un navegador con soporte para media queries, pero no para FlexBox simplemente linealizará el contenido en bloques que abarcan todo el ancho del dispositivo. Se quedarían en el orden del código fuente, pero todo el contenido será accesible para el usuario.

Como alternativa, las tablas CSS pueden utilizarse para eliminat un elemento del código fuente y ponerlo al principio o al final del contenido: mira el sucio hack table-caption y ríe entre dientes mientras das unos pasos atrás.

Resumen

Espero que este artículo te haya dejado claro exactamente lo impresionante y útil que es Flexbox, que nos permite acabar con los continuados abusos de float y clear, y toda una serie de otras técnicas de siseño horribles, "hacky" e inflexibles. También hemos visto lo genial que es Flexbox para el diseño web responsive cuando se combina con otras tecnologías, como las media queries.

Nota

Imagen de portada de Horia Varlan.

Logo Creative Commons
Los contenidos recogidos en este artículo están sujetos a una licencia Creative Commons
Reconocimiento, No comercial - Compartir bajo la misma licencia 3.0 No adaptada
.
: Ir al índice :