Guía interactiva de flexbox

Flexbox es una herramienta de maquetación my poderosa. Cuando realmente comprendemos cómo funciona, podemos crear diseños responsivos, es decir, se reorganizan según sea necesario.

Por ejemplo:

En pantallas con un ancho menor a 680px vas a tener algunos problemas apreciando todas las posibilidades de este diseño.

Esta demostración está fuertemente inspirada en el increíble codepen "4 diseños por el precio de 1" de Adam Argyle . No utiliza media queries o container queries. En lugar de establecer puntos de interrupción arbitrarios, utiliza flexbox para crear un diseño responsivo sin problemas.

Este es el CSS importante de éste formulario:

					
				
#flex-form {
display: flex ;
align-items: flex-end ;
flex-wrap: wrap ;
gap: 16 px ;
}
label[for='name'] {
flex-grow: 1 ;
flex-basis: 160 px ;
}
label[for='email'] {
flex-grow: 3 ;
flex-basis: 200 px ;
}
button {
flex-grow: 1 ;
flex-basis: 80 px ;
}

Introducción a Flexbox

CSS se compone de muchos algoritmos de diseño diferentes, conocidos oficialmente como "layout modes". Cada modo de diseño es su propio sub-lenguaje dentro de CSS. El modo de diseño predeterminado es “flow”, pero podemos optar por Flexbox cambiando la propiedad display en el contenedor padre:

Cuando cambiamos el display a flex, creamos un "contexto de formato flexible". Ésto significa que, de forma predeterminada, todos los elementos secundarios se colocarán de acuerdo con el algoritmo de diseño de Flexbox.

Cada algoritmo de diseño está diseñado para resolver un problema específico. El diseño predeterminado de "flow" está destinado a crear documentos digitales; es esencialmente el algoritmo de diseño de Microsoft Word . Los encabezados y los párrafos se apilan verticalmente como bloques, mientras que elementos como el texto, los enlaces y las imágenes se ubican discretamente dentro de estos bloques.

Entonces, ¿qué problema resuelve Flexbox? Flexbox se trata de organizar un grupo de elementos en una fila o columna, y nos brinda una cantidad ridícula de control sobre la distribución y alineación de esos elementos. Como sugiere el nombre, Flexbox tiene que ver con la flexibilidad. Podemos controlar si los artículos crecen o se encogen, cómo se distribuye el espacio adicional y más.

Flex Direction

Flexbox trata de controlar la distribución de elementos en una fila o columna.

De forma predeterminada, los elementos se acomodarán uno al lado del otro en una fila, pero podemos pasar a una columna con la propiedad flex-direction:

Con flex-direction: row, el eje principal es horizontal, de izquierda a derecha. Cuando cambiamos a flex-direction: column, el eje principal es vertical, de arriba a abajo.

¿Pero flex-direction: column es lo mismo que tener los elementos con display: block ? De manera visual: sí!

Y entonces para qué utilizo flex-direction: column ?

Ahhh... Excelente pregunta mi querido padawan. En Flexbox, todo se basa en el eje principal y al algoritmo no le importa si es vertical u horizontal, todas las reglas se estructuran en torno a este eje principal, y el eje secundario (secondary/cross axis) que se coloca de manera perpendicular al eje principal.

Y esto está muy cool! Porque cuando aprendemos las reglas de Flexbox, podemos cambiar sin problemas de diseños horizontales a verticales.

Todas las reglas se adaptan automáticamente. De hecho, esta función es exclusiva del modo de diseño Flexbox.

Los hijos se posicionan de acuerdo a 2 reglas:

  1. Eje principal: Los hijos se agruparán al inicio del contenedor.
  2. Eje secundario: Los hijos se estiran para llenar todo el contenedor.

Representación visual de los ejes en flexbox

Alineación

Es posible cambiar como es que los hijos se distribuyen sobre el eje principal utilizando la propiedad justify-content:

Cuando se trata del eje primario, no pensamos en términos de alinear a un solo hijo. En cambio, se trata de la distribución del grupo.

Podemos agrupar todos los elementos en un lugar particular (con flex-start, center y flex-end), o podemos separarlos (con space-between, space-around y space-evenly).

Para el eje secundario, las cosas son un poco diferentes. Aquí usamos la propiedad align-items:

Interesante... Con align-items, tenemos algunas de las mismas opciones que con justify-content, pero no exactamente las mismas.

justify-content

  • space-between
  • space-around
  • space-evenly

align-items

  • stretch
  • baseline
  • flex-start
  • center
  • flex-end

Align Self

A diferencia de justify-content y align-items, align-self se aplica a los hijos, no al contenedor padre.

align-self nos permite cambiar la alineación de un elemento específico a lo largo del eje secundario:

align-self tiene todos los mismos valores que align-items. De hecho, cambian exactamente lo mismo.

align-items es syntctic sugar(?). Esta propiedad establece automáticamente la alineación en todos los hijos a la vez.

Pero ojo 👀, no existe justify-self, bueno, al menos no en Flexbox

Content .vs. items

Hasta el momento, Flexbox parece ser my arbitrario. ¿Porqué es justify-content y align-items y no justify-items o align-content?

Y más aún, ¿porqué existe un align-self y no justify-self?

Esta es una de las cosas más importantes y menos comprendidas de Flexbox.

En Flexbox, los elementos se distribuyen la lo largo del eje principal.

De forma predeterminada, los elementos flexibles están alineados uno a lado del otro sobre el eje principal; y podemos dibujar una recta horizontal que atraviese a todos los elementos flexibles:

Primary Axis

En el eje secundario es diferente. Una linea cruza cada uno de los elementos flexibles:

Secondary Axis

Secondary Axis

Secondary Axis

De esta forma, es posible controlar cada uno de los elementos flexibles de manera independiente, al contrario del eje principal, en donde se mueven de manera conjunta.

Esta es la principal diferencia entre el eje principal y el eje secundario. Cuando hablamos del eje principal, los elementos se mueven en conjunto. En el eje secundario podemos controlarlos de manera individual.

Es por eso que no existe la propiedad justify-self. ¿Qué haríamos si es que un elemento tiene la propiedad justify-self: center? ¿Para dónde se mueve si hay elementos a su al rededor?

Con esto dicho, definamos los 4 términos:

No existe la propiedadjustify-items por lo mismo que no existe justify-self; cuando hablamos del eje principal, pensamos a los elementos como un grupo y no de manera individual.

Tamaño hipotético

Supongamos que tenemos el siguiente codigo CSS:

					
		
.item {
width : 500 px ;
}

Una persona razonable diría que el elemento con la clase item tiene un ancho de 500px.

Pero, lamento informarte, que no siempre es así...

							
								
<style>
.flex-wrapper {
display : flex ;
}
.item {
width : 500 px ;
}
</style>
<div class="item"></div>
<div class="flex-wrapper">
<div class="item"></div>
</div>

Resultado:

.item
.item

Interesante, no?

Ambos tienen la misma medida aplicada. Ambos .item tienen la propiedad width: 500px. Y aún así, el primer .item es mucho más grande que el segundo!

La diferencia es el modo de diseño. El primer .item está usando el modo de flow, en el cual, el width en una restricción estricta. Cuando establecemos width: 500px, obtendremos un elemento de 500 píxeles de ancho, incluso si tiene que salirse de nuestra pantalla.

En Flexbox, la propiedad width es más una sugerencia que una restricción. Y por eso tenemos un nombre para esto: tamaño hipotético. Este es el tamaño que un elemento tendrá en un mundo perfecto y si nada se opone en su camino.

En ejemplo anterior, el contenedor padre no tenía el espacio suficiente para contener un div de 500px de ancho. Y por tanto, el hijo (flex item) se ajusta a su contenedor padre(flex container).

Esta es una parte fundamental de la filosofía de Flexbox. Los elementos son fluidos y flexibles, y pueden ajustarse a las limitaciones del mundo.

Creciendo y encogiéndose

Entonces, hemos visto que el algoritmo Flexbox tiene cierta flexibilidad incorporada, con tamaños hipotéticos.

Pero para ver realmente cuán fluido puede ser Flexbox, necesitamos hablar sobre 3 propiedades: flex-grow, flex-shrink y flex-basis.

Estas propiedades se aplican a los elementos flexibles.

Flex basis

En una fila flex, flex-basis hace lo mismo que width. En una columna flex, flex-basis hace lo mismo que height.

Los autores de Flexbox crearon una propiedad genérica de "tamaño" llamada flex-basis. Es como width o height, pero vinculado al eje primario, como todo lo demás.

flex-basis nos permite establecer el tamaño hipotético de un elemento sobre el eje principal , independientemente de si es horizontal o vertical.

El elemento seleccionado tiene asignada la propiedad de flex-basis: 50px; por defecto, intenta cambiarla y averiguar qué sucederá.

flex-basis es más una sugerencia que una restricción estricta. En cierto punto, simplemente no hay suficiente espacio para que todos los elementos se asienten en su tamaño asignado, por lo que tienen que comprometerse para evitar un desbordamiento.

Flex grow

Por defecto, los elementos en un contexto flex se reducirán a su tamaño mínimo cómodo a lo largo del eje principal. Esto a menudo crea espacio adicional.

Lo que nos da chance de especificar cómo se debe consumir ese espacio con la propiedad flex-grow:

El espacio que sobra dentro del contenedor se agrega directamente al elemento que tiene definida la propiedad flex-grow con el valor de 1.

El valor por defecto para flex-grow es 0, lo que significa que el crecimiento es opcional. Si queremos que un elemento flex ocupe cualquier espacio adicional en el contenedor, debemos decírselo explícitamente.

¿Y qué pasa si se establezco varios elementos flex con la propiedad flex-grow?

En este caso, mi querida tortuga ninja, el espacio extra se reparte entre los elementos, proporcionalmente en función de su valor flex-grow.

Expliquémoslo de manera visual. Intenta incrementar/decrementar cada elemento flex:

El primer elemento quiere 1 unidad de espacio adicional, mientras que el segundo elemento quiere 1 unidad. Eso significa que el número total de unidades es 2 ( 1 + 1 ). Cada elemento recibe una parte proporcional de ese espacio extra.

Flex shrink

En los ejemplos que hemos visto hasta ahora, hemos tenido espacio adicional para trabajar. Pero, ¿y si nuestros elemento son demasiado grandes para su contenedor?

Intenta encoger el contenedor para ver qué sucede:

Interesante, ¿verdad? Ambos elementos se encogen, pero se encogen proporcionalmente. El primer elemento siempre mide 2 veces el ancho del segundo elemento.

Como recordatorio, flex-basis tiene el mismo propósito que width. Estamos usando flex-basis porque es lo convencional al usar el modo de diseño Flexbox, ¡pero obtendríamos exactamente el mismo resultado si usáramos width!

flex-basis y width establecen el tamaño hipotético de los elementos. El algoritmo Flexbox puede reducir los elementos por debajo del tamaño deseado, pero de forma predeterminada. Siempre se escalarán juntos, preservando la proporción entre ambos elementos.

Ahora, ¿qué pasa si no queremos que nuestros elementos se reduzcan proporcionalmente? Ahí es donde entra la propiedad flex-shrink.

Tómate un par de minutos, a ver si puedes averiguar qué está pasando aquí:

Tenemos dos elementos, cada uno con un tamaño hipotético de 200px. El contenedor debe tener al menos 400px de ancho para contener a estos elementos en su tamaño hipotético.

Supongamos que encogemos el contenedor a 300px. Bueno, ¡no podemos meter 400px de contenido en un contenedor de 300px! Tenemos un déficit de 100px. Nuestros elementos deberán ceder 100px en total para que encajen.

La propiedad flex-shrink nos permite decidir como se paga este déficit/deuda.

De la misma manera que flex-grow, es una proporción. El valor por defecto de esta propiedad es flex-shrink: 1, por lo que cada elemento paga la mitad de la deuda. Cada uno pierde 50px y su tamaño real se reduce de 200px a 150px.

Ahora, supongamos que elevamos la propiedad flex-shrink a 3 en el primer elemento flexible:

actual size, flex-shrink & reduced by

Tenemos un déficit total de 100px. Normalmente, cada elemento pagaría ½, pero debido a que hemos jugado con el flex-shrink, el primer elemento termina pagando ¾ partes de 100px (75px) y el segundo elemento paga ¼ partes de 100px (25px).

Tengamos en cuenta que los valores absolutos no importan, se trata de la proporción. Si ambos elementos tienen flex-shrink: 1, cada elemento pagará la mitad del déficit total. Si ambos elementos se elevan a flex-shrink: 1000, cada elemento pagará 1000/2000 del déficit total. Siempre funciona igual.

Podemos pensar en que flex-shrink es el "inverso" de flex-grow. Son dos caras de la misma moneda:

Esto significa que solo una de estas propiedades puede estar "activa" a la vez. Si hay espacio extra, flex-shrink no tiene efecto, ya que los elementos no necesitan encogerse. Y si los elementos son demasiado grandes para su contenedor, flex-grow no tiene efecto, porque no hay espacio extra para repartir.

Gap

Una de las mayores mejoras que tuvo Flexbox en los últimos años ha sido la propiedad gap:

gap nos permite crear un espacio entre cada elemento Flex. Esto es genial para cosas como las barras de navegación:

gap es una adición relativamente nueva al lenguaje Flexbox, se implementó en todos los navegadores modernos desde principios del 2021.

Así es... Flexbox se tomó muy en serio la sana distancia.

Auto margin

Hay otro truco relacionado con el espacio que quiero compartir. Ha existido desde los primeros días de Flexbox, pero es relativamente oscuro y alucinante.

La propiedad margin se utiliza para agregar espacio alrededor de un elemento específico. De hecho, en algunos modos de diseño, como flow y positioning, se puede usar para centrar un elemento, con margin: auto.

Los márgenes automáticos son mucho más interesantes en Flexbox:

Los márgenes automáticos se comerán el espacio adicional y lo aplican al margen del elemento. Nos da un control preciso sobre dónde distribuir el espacio extra sin estirar al elemento como flex-grow lo hace.

Wrapping

¡Uf! Hemos cubierto muchas cosas hasta ahora. Pero hay una ultima propiedad que me gustaría cubrir.

Hasta ahora, todos nuestros elementos se han posicionado lado a lado, en una sola fila o columna. La propiedad flex-wrap nos permite cambiar eso.

La mayoría de las veces, cuando trabajamos en dos dimensiones, preferimos usar CSS Grid, ¡pero Flexbox + flex-wrap definitivamente tiene sus usos!

Este ejemplo en particular muestra el diseño de "panqueque deconstruido", donde los elementos se apilan en una pirámide invertida en pantallas de tamaño mediano.

Cuando establecemos la propiedad flex-wrap con el valor wrap, los elementos flexibles no se encogen más allá de su tamaño ideal (flex-basis). Bueno, al menos, no mientras pasarse a la siguiente fila o columna sea una opción.

Oyeee! ‘Perate, ‘perate! ¿Qué pasa con lo que habíamos dicho de que existía un solo eje primario?

Con flex-wrap: wrap, ya no vamos a tener un solo eje primario. Efectivamente, cada renglón (o columna) se comportará como un mini-contenedor flexible y por ende, cada uno tendrá su propio eje principal.

Animacion de multiples ejes principlaes

Afortunadamente, todas la reglas que hemos visto hasta ahora siguen aplicando de la misma manera

Pero, ¿como va a funcionar la propiedad align-items ahora que tenemos multiples renglones? El eje secundario ahora puede cruzar a varios elementos!

Toma un momento para considerar esto. ¿Qué crees que sucederá cuando cambiemos la propiedad de align-items a los valores que ya conocemos?

En pantallas con un ancho menor a 740px no podemos apreciar el efecto que tiene flex-wrap

Cada uno de los renglones es su propio mini-contenedor flexible. align-item mueve a cada elemento flexible hacia arriba o hacia abajo dentro de la caja invisible que envuelve a cada uno de los renglones.

¿Y si ahora quiero alinear a los renglones de manera diferente? Eso lo podemos hacer con la propiedad align-content:

En pantallas con un ancho menor a 740px no podemos apreciar el efecto que tiene flex-wrap

Cabe aclarar que los elementos flexibles necesitan espacio para moverse. Si no lo tienen disponible, no veremos grandes cambios.

Para resumir:

Y ya 💁‍♀️

Estuvo tranqui, ¿no?

Claramente hay mucha información que procesar y, es que, analizamos cada una de las propiedades de manera exhaustiva.

En el día a día, no es necesario comprender en dónde queda cada uno de los pixeles, pero es bastante útil tener una guía cuando las cosas no funcionan como esperábamos.

Así que no pretendo que memorices toda la información que hay aquí, ¡si no que la utilices como apoyo para tus siguientes proyectos! Tus rueditas traseras de bicicleta, por decirlo de alguna manera.