Flexbox es el chico nuevo en CSS, de ser un tema conversado con cierto misticismo en los foros empieza a convertirse en un tema imprescindible para quienes desarrollamos aplicaciones y páginas web. Hoy muchos saben que poniendo display:flex
suceden cosas mágicas. Sin embargo, necesitamos comprender a fondo la teoría para sacarle el mayor provecho.
Y es que Flexbox no se puede simplificar a una lista de propiedades y valores, sino que se requiere un conocimiento profundo de qué está pasando internamente con los elementos (por ejemplo, ¿Qué sucede con los márgenes, paddings, altos, anchos?). Estamos ante un amplio concepto que nos obliga a reaprender lo que hemos hecho por años (como tuvimos que reaprender conceptos al enfrentarnos al Responsive Web Design). Y es que Flexbox no es una propiedad, flexbox es un nuevo modelo de layout (y se viene otro: grid
; que hará que exploten más cerebros aún). Pero vamos de lleno al tema.
Qué es flexbox
Flexbox no es una propiedad ni un cojunto de propiedades. Flexbox es un nuevo modelo de layout que viene a incorporarse a los ya existentes en css (se esta trabajando actualmente en nuevo modelo: el grid layout):
- Block (los elementos aparecen uno debajo de otro ocupando todo el ancho disponible)
- Inline (los elementos aparecen uno al lado del otro en una linea y saltan a la linea siguiente al ocupar el espacio disponible)
- Table (los elementos imitan la distribución de una tabla HTML, con filas, encabezados y columnas).
- Positioned (los elementos pueden romper el flujo y posicionarse en cualquier lugar del documento):
Un modelo de layout es un set de algoritmos que determinan el tamaño y la posición de los elementos con respecto a sus hermanos y ancestros.
¿Qué se puede hacer con flexbox?
Teniendo lo que significa un modelo de layout, con flexbox podemos hacer lo siguiente:
- Distribuir los elementos en sentido vertical u horizontal
- Reordenar la aparición de los elementos sobreescribiendo su aparición en el navegador.
- Ajustar dinámicamente las dimensiones de los elementos para evitar desbordamientos (overflow) respecto a su padre.
- Redefinir el sentido del flujo de los elementos (hacia arriba, hacia abajo, hacia la izquierda o hacia la derecha).
- Alinear los elementos respecto al padre o respecto a sus hermanos.
Soporte de los navegadores
El soporte es al 100% para Firefox, Chrome, Opera (escritorio y moviles) e IE11. Los únicos navegadores que dan problemas son los culpables de siempre: IE y Safari.
- Safari (escritorio y movil) requiere el prefijo -webkit-
- IE10 soporta flexbox con el prefijo -ms- pero con la sintaxis del 2012 (se indicará en los ejemplos de este artículo)
- IE9- no soportan flexbox. Así que si por alguna extraña razón necesitas dar soporte a esos navegadores, sube a tu Delorian y viaja al pasado.
Por otro lado, estamos a casi un mes del lanzamiento de Windows 10 y Su nuevo navegador Edge (que remplazará definitivamente a IE) por lo que es momento de usar Flexbox.
Flex container y flex items
Lo primero que debes saber sobre Flexbox, es que para funcionar necesita que se defina un contexto. Para usar flexbox debes trabajar en conjunto con el contenedor y sus hijos. No hay forma de manipular directamente un elemento con flexbox sin crear antes su contexto. La convención es llamar al contenedor: flex-container y a sus hijos: flex-items.
El contexto se define asignando display:flex
a un elemento. Eso hace que sus hijos directos se conviertan en flex-items (es decir, cajas flexibles) y puedan manipularse con flexbox. Dicho esto, existen propiedadees que aplican al flex-container y otras que aplican a los flex-items, aunque no vamos a profundizar sobre eso ahora.
Solo recuerda que el flex-container define el contexto para trabajar con flexbox. Usando display:flex
se define un contexto de tipo block. En cambio display: flex-inline
define un contexto del tipo inline (con el espaciado característico de los elementos inline e inline-block).
Además a los flex-items se les puede asignar display:flex
con lo que se definiría un nuevo contexto en cada uno para sus hijos. No hay limite para este tipo de anidación.
display: flex | inline-flex;
/*
display: -ms-flexbox | -ms-inline-flexbox (IE10)
display: -webkit-flex (Safari)
*/
Consideraciones con el flex-container y los flex-items
- Un texto incluido directamente en un flex-container es envuelto en un flex-item anónimo. Salvo que el texto sea solo espacios, en ese caso, es lo mismo que si tuviera display: none;
- Float and clear no aplican a los flex-items.
- Vertical-align no aplica a los flex-items
- Ls propiedades de columnas column-* no aplican en el flex-container.
Main Axis y Cross Axis
Lo segundo que debes saber es que al definir un contexto para flexbox, internamente cambian muchas cosas, aunque no las puedas ver. Lo principal es que se crean dos ejes: el main axis (principal) y el cross axis (secundario). Estos ejes permiten distribuir y alinear los elementos respecto a ellos y mucha gente se confunde sobre este aspecto. Así que mira detenidamente la siguiente imagen (extraida de la especificación de la W3C):
Como ves, hay dos ejes. Pero no solo eso, sino que cada eje tiene un inicio (start) y un final (end). De manera predeterminada el eje principal (main axis) es horizontal y su sentido es de izquierda a derecha. Y el eje secundario (cross axis) es vertical y su sentido es de arriba hacia abajo. Además, se definen dos nuevas dimensiones que vienen a sustituir (en ciertas circunstancias) al height y width de los flex-items; estas son main size y cross size (relativas a los ejes y que veremos en detalle en otro post).
El sentido de los ejes está determinado por el sentido de la escritura del documento. Algunos idiomas (como los asiáticos) escriben de derecha a izquierda (rtl, right to left) por lo que, en ese caso, el sentido de los ejes será inverso a lo expuesto aqui. Si bien muy pocas veces usarás documentos con dirección rtl no está de más saberlo.
Además, puedes cambiar el eje principal y el sentido usando flex-direction. Es decir, puedes decidir que el main axis sea vertical, o que el sentido sea de derecha a izquierda o de abajo hacia arriba. Esto se consigue con la propiedad flex-direction
(aplicada al flex-container).
flex-direction: row (default) | column | row-reverse | column-reverse
/*
-ms-flex-direction (IE9)
-webkit-flex-direction (Safari)
*/
/*
Según el valor indicado, el main axis será:
row: horizontal, izquierda a derecha
row-reverse: horizontal, derecha a izquierda
column: vertical, de arriba hacia abajo
column-reverse: vertical, de abajo hacia arriba
*/
Ten en cuenta, que los elementos se distribuyen respecto al eje principal y con el sentido de él. Por lo que al cambiar su orientación y sentido, los flex-items se reordenarán. La siguiente imagen lo explica mejor.
Distribuir en el main axis con justify-content
Con la propiedad justify-content
podemos distribuir el espacio disponible entre los elementos respecto al main axis. Recuerda que el main axis puede ser horizontal o vertical, según como lo hayamos definido con flex-direction
. Por lo tanto, es un error común creer que justify-content
alinea horizontalmente (también puede hacerlo verticalmente)
justify-content: flex-start (default) | flex-end | center | space-around | space-between
/*
-ms-flex-pack: start | end | center | justify; (IE10, no existe space-around, justify remplaza a space-between)
-webkit-justify-content (Safari)
*/
/* Distribución de los elementos en el main axis
flex-start: al inicio del main axis
flex-end: al final del main axis
center: al medio del main axis
space around: calcula el espacio libre y lo distribuye alrededor de los flex-items
space-between: calcula el espacio libre y lo distribute entre los flex-items
*/
La siguiente imagen lo explica mejor:
Alinear en el cross-axis con align-items
La propiedad align-items
(aplicada al flex-container) alinea los elementos respecto al cross axis. Nuevamente, recuerda que aunque de manera predeterminada, el cross axis es vertical, podría ser también horizontal, si así lo definimos en flex-direction. Así que también en este caso, es un error decir que align-items
se usa para alineación vertical.
El valor por defecto de esta propiedad (si no se la declara) es stretch
, que hace que los flex-items ocupen todo el espacio disponible en el cross axis. Siempre que no tengan esa dimensión definida.
align-items: stretch (default) | flex-start | flex-end | center | baseline
/*
-ms-flex-align (IE10)
-webkit-align-items (Safari)
*/
/*
Alineación de los elementos en el cross axis
stretch: los flexitems rellenan todo el espacio disponible en el cross axis (si no se ha definido su dimensión)
flex-start: al inicio del cross axis
flex-end: al final del cross axis
center: al medio del cross axis
baseline: toma como referencia la linea base del texto y los elementos inline (como imágenes)
*/
La siguiente imagen lo explica mejor:
Alinear un flex-item unico con align-self
A diferencia de las propiedades ya vistas, align-self
se aplica a un flex-item unico y no al flex-container. Esta propiedad permite posicionar un flex-item específico respecto al cross axis. El comportamiento es idéntico al de align-items, la diferencia es que se aplica a un único flex-item.
align-self: auto (default) | flex-start | flex-end | center | baseline | stretch
/*
-ms-flex-item-align (IE10)
-webkit-align-self (Safari)
*/
Centrado absoluto con Flexbox
Uno de los mayores retos del CSS tradicional siempre ha sido el centrado absoluto (centrar vertical y horizontalmente). Con flexbox el reto ha desaparecido. Basta aplicar lo aprendido al flex-container:
.flex-container{
display: flex;
justify-content: center;
align-items: center;
}
Dibujar un dado con Flexbox
Este es un interesante y sencillo ejercicio planteado por Landon Schropp y que permite poner a prueba nuestros conocimientos de alineación en el eje principal y en el eje secundario (lo aprendido en este artículo). Puedes ver el artículo original aqui: http://davidwalsh.name/flexbox-dice y una demostración en el siguiente codepen:
See the Pen Flexbox Dice by Landon Schropp (@LandonSchropp) on CodePen.
Esto es solo el inicio
Flexbox es mucho más de lo que hemos visto en este artículo y en otros posts continuaremos desarrollándolo a fondo.