Skip to content
This page has been auto-translated and may contain errors.View in English

Flexbox ​

Quieres tres botones en una fila, espaciados de forma pareja, todos con la misma altura, y centrados verticalmente sin importar cuánto texto tenga cada uno. Antes esto significaba floats, clearfixes y bastante adivinación. Flexbox es la herramienta pensada justo para esto: le dices a un contenedor que acomode a sus hijos en línea, y luego los ajustas a lo largo de dos ejes hasta que queden donde quieres. Buena parte del diseño cotidiano que ves en la web, barras de navegación, barras de herramientas, filas de tarjetas, tiene un contenedor flex por debajo.

El contenedor flex ​

Flexbox empieza con una sola línea en un elemento padre. Configura display: flex en un contenedor y sus hijos directos se alinean en una fila, uno al lado del otro. Ese contenedor ahora es un contenedor flex, y cada hijo dentro de él se convierte en un elemento flex.

css
.nav {
  display: flex;    /* los hijos ahora se acomodan en fila */
}

Los elementos se distribuyen a lo largo de dos direcciones. El eje principal va de izquierda a derecha, la forma en que se alinean los elementos. El eje transversal va de arriba hacia abajo, atravesando la fila. Vas a mover elementos a lo largo de ambos, así que conviene visualizarlos desde ahora: el eje principal es la línea sobre la que se apoyan los elementos, el eje transversal es la dirección que la cruza.

display: flex convierte a un elemento en un contenedor flex y a sus hijos directos en elementos flex. Solo los hijos directos participan; cualquier cosa anidada más profundo la organiza su propio padre. Por defecto los elementos se acomodan en una fila, de izquierda a derecha, cada uno reducido al ancho de su contenido.

css
.nav {
  display: flex;    /* los hijos directos se vuelven una fila de elementos flex */
}

Todo el modelo funciona con dos ejes. El eje principal es la dirección en la que fluyen los elementos, una fila por defecto, o sea de izquierda a derecha. El eje transversal es perpendicular a él, y va de arriba hacia abajo. Cada propiedad de alineación que vas a encontrar trabaja sobre uno u otro eje, así que tener los dos bien claros es lo que hace que el resto encaje.

display: flex le da a un elemento un contexto de formato flex: sus hijos directos se convierten en elementos flex y se organizan mediante el algoritmo flex en lugar del flujo normal. Solo participan los hijos directos; los fragmentos de texto y los descendientes anidados se manejan por debajo de ellos. Este es el mismo tipo de límite que detiene el colapso de márgenes, una de las razones por las que los diseños flex se comportan de forma más predecible que la era de floats y clears que vinieron a reemplazar.

css
.nav {
  display: flex;    /* establece un contexto de formato flex */
}

Dos ejes gobiernan todo. El eje principal lo define flex-direction (una fila por defecto, o sea de inicio-en-línea a fin-en-línea), y el eje transversal es perpendicular a él. La distinción no es cosmética: justify-content siempre actúa a lo largo del eje principal y align-items siempre actúa a lo largo del eje transversal, así que en el momento en que cambias flex-direction a column, esas dos propiedades intercambian la dirección en la que empujan. Nombrar el diseño por eje en lugar de por "horizontal" y "vertical" es lo que mantiene la coherencia cuando cambia la dirección.

css
.nav {
  display: flex;
}

Una sola declaración, y los hijos de cualquier bloque dejan de apilarse de arriba hacia abajo y empiezan a acomodarse en fila. Todo lo demás en este capítulo trata de cómo dirigir esos elementos una vez que están dentro del contenedor.

JunoEl contenedor flex Pon display: flex en un padre y sus hijos directos se alinean en una fila. Ese padre es el contenedor flex, los hijos son elementos flex. Los elementos se mueven a lo largo de dos direcciones: el eje principal es la línea sobre la que se apoyan, el eje transversal la atraviesa, y vas a empujar elementos a lo largo de ambos.
JunoEl contenedor flexdisplay: flex hace que un contenedor acomode a sus hijos directos como una fila de elementos flex. Solo participan los hijos directos, no nada anidado más profundo. Ten claros los dos ejes: el eje principal es la dirección del flujo, el eje transversal es perpendicular, y cada propiedad de alineación trabaja sobre uno u otro.
JunoEl contenedor flexdisplay: flex inicia un contexto de formato flex, así que los hijos directos se organizan mediante el algoritmo flex y los márgenes dejan de colapsar dentro de él. Nombra el diseño por eje, no por horizontal y vertical, porque justify-content sigue el eje principal y align-items el eje transversal. Cambia flex-direction a column y esas dos propiedades intercambian hacia dónde empujan.

Alinear a lo largo de los ejes ​

Una vez que tus elementos están en fila, dos propiedades los mueven de lugar. justify-content los espacia a lo largo del eje principal, la dirección en la que se acomodan. align-items los mueve a lo largo del eje transversal, hacia arriba y abajo dentro de la fila.

css
.nav {
  display: flex;
  justify-content: space-between;   /* separa los elementos a lo largo de la fila */
  align-items: center;              /* los alinea en el centro vertical */
}

Los valores comunes de justify-content son flex-start (agrupados a la izquierda), center (agrupados al centro), flex-end (agrupados a la derecha), space-between (espacios entre elementos, ninguno en los extremos) y space-around (espacios a ambos lados de cada elemento). Para align-items, center es el que más vas a usar.

Para centrar algo en ambas direcciones, el truco que todos aprenden primero: pon los dos en center.

css
.hero {
  display: flex;
  justify-content: center;   /* centrado a lo largo del eje principal */
  align-items: center;       /* centrado a lo largo del eje transversal */
}

Dos propiedades se encargan de la alineación, una por eje. justify-content distribuye los elementos a lo largo del eje principal, y align-items los ubica en el eje transversal. Como cada una controla un eje distinto, nunca se contradicen entre sí, apuntan en direcciones perpendiculares.

css
.nav {
  display: flex;
  justify-content: space-between;   /* distribuye los elementos a lo largo del eje principal */
  align-items: center;              /* los centra en el eje transversal */
}

Para justify-content, los valores que conviene conocer son flex-start, center, flex-end, space-between (espacios iguales entre elementos, pegados a los bordes) y space-around (espacio igual alrededor de cada elemento, así que los espacios de los extremos son la mitad de los del medio). Para align-items, el valor por defecto es stretch, que hace que cada elemento llene la altura del contenedor, y por eso una fila de tarjetas sale con la misma altura aunque su contenido sea distinto. Configura align-items: center y vuelven a encogerse a la altura de su contenido y se ubican en el medio en cambio.

Centrar en ambos ejes es el par de propiedades que hizo famoso a flexbox:

css
.hero {
  display: flex;
  justify-content: center;   /* eje principal */
  align-items: center;       /* eje transversal */
}

La alineación se divide claramente por eje. justify-content distribuye el espacio libre a lo largo del eje principal, y align-items establece la posición por defecto en el eje transversal de cada elemento. No pueden entrar en conflicto porque operan sobre ejes perpendiculares, pero ambas dependen de cuál dirección es la "principal", así que un flex-direction: column intercambia lo que controla cada una.

css
.nav {
  display: flex;
  justify-content: space-between;   /* el espacio libre va entre los elementos */
  align-items: center;              /* cada elemento centrado en el eje transversal */
}

La distinción que suele confundir es que justify-content solo tiene algo que hacer cuando sobra espacio en el eje principal. Distribuye espacio libre, así que si los elementos ya llenan el contenedor (o lo desbordan), space-between y center se ven idénticos porque no hay nada que distribuir. align-items, en cambio, posiciona cada elemento de forma independiente dentro del tamaño transversal del contenedor, y su valor inicial es stretch: los elementos sin un tamaño fijo en el eje transversal crecen hasta llenar el contenedor. La fila de tarjetas con la misma altura es align-items: stretch cumpliendo su función por defecto. Puedes anularlo por elemento con align-self, que se cubre en la sección de tamaños más abajo.

css
.hero {
  display: flex;
  justify-content: center;   /* centrado en el eje principal */
  align-items: center;       /* centrado en el eje transversal, anula el stretch por defecto */
}

Dos elementos y un min-height en el contenedor, ambos configurados en center, y ya resolviste el problema de centrado que a toda una generación de desarrolladores le tomó simular con posicionamiento absoluto y márgenes negativos.

JunoAlinear a lo largo de los ejesjustify-content espacia los elementos a lo largo del eje principal, align-items los mueve a lo largo del eje transversal. Los valores que hay que recordar para el primero son center, space-between y flex-start. Pon los dos en center y lo que sea que esté adentro queda exactamente en el medio, un truco de diseño que vas a usar una y otra vez.
JunoAlinear a lo largo de los ejes Una propiedad por eje: justify-content en el eje principal, align-items en el transversal. El valor por defecto align-items: stretch es la razón por la que una fila de tarjetas sale con la misma altura sin que lo pidas. Y ambas en center es el truco para centrar cualquier cosa que vale la pena memorizar.
JunoAlinear a lo largo de los ejesjustify-content distribuye el espacio sobrante del eje principal, así que si los elementos ya llenan la fila no hace nada, lo cual explica muchos momentos de "por qué esto no se centra". align-items posiciona cada elemento en el eje transversal y por defecto usa stretch, dándote filas de igual altura sin esfuerzo. Cambia flex-direction y recuerda que ambas propiedades intercambian el eje sobre el que actúan.

Dirección y ajuste de línea ​

Por defecto, un contenedor flex acomoda los elementos en fila. Cambia eso con flex-direction. Configúralo en column y los elementos se apilan de arriba hacia abajo en lugar de quedar uno al lado del otro.

css
.sidebar {
  display: flex;
  flex-direction: column;   /* ahora los elementos se apilan verticalmente */
}

Cuando los elementos en una fila se quedan sin espacio, se van comprimiendo cada vez más. Para que en cambio pasen a una nueva línea, agrega flex-wrap: wrap.

css
.card-row {
  display: flex;
  flex-wrap: wrap;   /* los elementos que no caben pasan a la siguiente línea */
}

Para el espacio entre elementos, usa gap. Agrega un espacio uniforme entre cada elemento sin añadir espacio en los bordes exteriores.

css
.card-row {
  display: flex;
  gap: 16px;   /* 16px entre cada elemento */
}

flex-direction define el eje principal. El valor por defecto, row, va de izquierda a derecha; column vuelve vertical el eje principal, así que los elementos se apilan de arriba hacia abajo y, esto es importante, justify-content ahora controla el espaciado vertical mientras que align-items controla el horizontal. También existen row-reverse y column-reverse si necesitas invertir el orden.

css
.sidebar {
  display: flex;
  flex-direction: column;   /* el eje principal ahora es vertical */
  justify-content: center;  /* lo que significa que esto centra verticalmente */
}

Por defecto, una línea flex nunca se corta: los elementos se encogen para caber en lugar de saltar de línea. Configura flex-wrap: wrap y los elementos que no entran pasan a una nueva línea, lo que hace posible una grilla de tarjetas responsiva sin usar media queries.

css
.card-row {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;   /* gap funciona en ambos ejes: 16px entre filas y columnas */
}

Usa gap para el espaciado, no márgenes en los elementos. gap se aplica solo entre elementos, nunca en los bordes exteriores, así que nunca tienes que quitar un margen sobrante del último hijo.

flex-direction define el eje principal, y toda propiedad que dependa del eje lo sigue. row (el valor por defecto) hace horizontal el eje principal; column lo hace vertical y reasigna en silencio justify-content al espaciado vertical y align-items al horizontal. Las variantes -reverse invierten la dirección del eje principal, pero ten en cuenta que solo reordenan visualmente: el orden del DOM no cambia, así que el orden de teclado y de lector de pantalla sigue el orden del código fuente, algo que es una consideración real de accesibilidad cuando usas row-reverse.

css
.sidebar {
  display: flex;
  flex-direction: column;    /* eje principal vertical; justify-content ahora centra verticalmente */
  gap: 8px;
}

flex-wrap: wrap levanta la restricción de una sola línea. Sin él, un contenedor flex fuerza a todos los elementos a una sola línea y distribuye cualquier faltante encogiéndolos; con él, los elementos que desbordan el tamaño principal saltan a nuevas líneas, y el contenedor se vuelve de varias líneas. Una vez que el ajuste está activo, align-content (distinto de align-items) rige cómo se espacian las líneas en el eje transversal. gap define el espacio entre elementos y, cuando hay ajuste, entre líneas, y es la herramienta correcta: a diferencia de los márgenes, no colapsa nada, no agrega espacio en los bordes, y se lee como una única decisión de espaciado.

css
.card-row {
  display: flex;
  flex-wrap: wrap;
  gap: 16px 24px;   /* row-gap 16px, column-gap 24px */
}

Aquí también aparece el límite con CSS grid. El ajuste de flex llena una línea y luego corta, así que los elementos en diferentes filas no se alinean en columnas. Cuando necesitas una verdadera grilla bidimensional con filas y columnas alineadas, ese es trabajo de grid, no de flexbox.

JunoDirección y ajuste de líneaflex-direction: column apila los elementos verticalmente en lugar de en fila. flex-wrap: wrap deja que los elementos pasen a una nueva línea cuando se quedan sin espacio, en lugar de comprimirse. Y gap pone un espacio uniforme entre elementos sin agregar nada en los bordes, así que úsalo antes que los márgenes.
JunoDirección y ajuste de líneaflex-direction define el eje principal, y cambiar a column significa que justify-content ahora espacia verticalmente, algo que sorprende a la gente la primera vez. flex-wrap: wrap es lo que hace que una fila de tarjetas se reacomode sin media queries. Usa gap para el espaciado así nunca tienes que perseguir un margen suelto en el último elemento.
JunoDirección y ajuste de líneaflex-direction define el eje principal y toda propiedad basada en el eje lo sigue, mientras que los valores -reverse reordenan visualmente pero dejan intactos el orden del DOM y del foco, así que úsalos con cuidado. flex-wrap vuelve multilínea al contenedor y le pasa el espaciado de línea a align-content. Cuando los elementos ajustados necesitan alinearse en columnas reales, eso es grid, no flexbox.

Tamaño flexible de los elementos ​

El punto de flexbox es que los elementos pueden ser flexibles, creciendo o encogiéndose para compartir el espacio. La abreviatura que más vas a usar es flex: 1 en un elemento, que le dice que crezca y tome una parte igual del espacio disponible.

css
.card {
  flex: 1;   /* cada tarjeta crece para llenar una parte igual de la fila */
}

Pon flex: 1 en tres tarjetas en una fila y dividen el contenedor en tres anchos iguales. Dale a una tarjeta flex: 2 y toma el doble de espacio que las demás. Ese único número es cómo los elementos se reparten el espacio sobrante entre ellos.

Detrás de flex: 1 hay tres controles separados: cuánto crece un elemento, cuánto se encoge, y su tamaño inicial. Rara vez los configuras uno por uno al principio, la abreviatura cubre los casos comunes, pero ayuda saber que están ahí.

Tres propiedades determinan cómo los elementos comparten el espacio. flex-grow define cuánto crece un elemento para llenar el espacio sobrante (0 significa que no crece). flex-shrink define cuánto cede cuando el espacio escasea (1, el valor por defecto, significa que puede encogerse). flex-basis define el tamaño inicial del elemento antes de crecer o encogerse, y por defecto es auto, es decir "usa el contenido o el ancho".

La abreviatura flex agrupa las tres, y los valores que realmente vas a escribir son pocos:

css
.card {
  flex: 1;   /* crece 1, se encoge 1, base 0: columnas de igual ancho */
}

.sidebar {
  flex: 0 0 240px;   /* no crece, no se encoge, se queda en 240px */
}

flex: 1 es el más usado: hace que los elementos dividan la fila en partes iguales sin importar su contenido, porque la base 0 hace que empiecen desde nada y crezcan solo según su factor de crecimiento. flex: 0 0 240px es el sidebar de ancho fijo junto a un área principal con flex: 1, un diseño que vas a construir constantemente.

El tamaño de los elementos se resuelve a través de tres propiedades que el contenedor evalúa en orden. flex-basis es el tamaño inicial del elemento en el eje principal, tomado antes de que se distribuya cualquier espacio libre; su valor por defecto auto remite al width del elemento (o al tamaño del contenido). Luego el contenedor mide la diferencia entre la suma de los valores de base y su propio tamaño. Si hay espacio libre, se reparte proporcionalmente al flex-grow de cada elemento. Si hay un faltante, se recupera proporcionalmente al flex-shrink de cada elemento, ponderado por su base.

css
/* flex: 1 se expande a flex-grow: 1, flex-shrink: 1, flex-basis: 0% */
.card {
  flex: 1;   /* base 0, así que los elementos ignoran el ancho del contenido y dividen el espacio por el factor de crecimiento */
}

La parte sutil es flex-basis frente a width, porque interactúan entre sí. flex-basis: 0 (como en flex: 1) hace que los elementos ignoren su contenido y dividan el espacio solo por el factor de crecimiento, dando columnas verdaderamente iguales. flex-basis: auto (como en flex: auto, o un simple width) hace que cada elemento empiece con su contenido o ancho declarado y solo después comparta el resto, así que los elementos con más contenido terminan siendo más anchos. Elegir entre uno y otro es en realidad decidir si el contenido debe influir en los anchos finales.

Dos observaciones de uso real. Primero, flex-basis gana sobre width cuando ambos están definidos, así que una vez que un elemento es un elemento flex, conviene expresar su tamaño mediante flex. Segundo, la trampa del desbordamiento: un elemento flex tiene por defecto min-width: auto, lo que significa que se niega a encogerse por debajo del tamaño intrínseco de su contenido, así que una palabra larga o un hijo que se desborda pueden reventar toda la fila. La solución es min-width: 0 en el elemento al que se le debe permitir encogerse.

css
.main {
  flex: 1;
  min-width: 0;   /* permite que este elemento se encoja por debajo de su contenido, así el texto largo se trunca en vez de desbordarse */
}

align-self anula align-items para un solo elemento, así que uno puede quedar en flex-start mientras el resto se centra. Y en cuanto a elegir la herramienta correcta: usa flexbox para diseños unidimensionales, una barra de navegación, una barra de herramientas, una sola fila o columna de elementos. Cuando necesitas filas y columnas alineadas al mismo tiempo, CSS grid es la herramienta indicada. Si no estás seguro de cómo se resuelven los anchos por debajo de todo esto, las unidades de tamaño explica cómo se comportan los porcentajes y otras unidades aquí.

css
.layout {
  display: flex;
  gap: 24px;
}
.sidebar {
  flex: 0 0 240px;   /* fijo en 240px, nunca crece ni se encoge */
}
.main {
  flex: 1;           /* toma todo el espacio restante */
}

Un sidebar fijo junto a una columna principal flexible, tres líneas de intención. Este patrón, sumado a la barra de navegación alineada de antes, cubre una gran parte de los diseños que vas a construir.

JunoTamaño flexible de los elementosflex: 1 en un elemento le dice que crezca y tome una parte igual de la fila, así que tres tarjetas con flex: 1 salen del mismo ancho. Cambia una a flex: 2 y toma el doble de espacio. Ese único número es cómo los elementos flex se reparten el espacio entre ellos.
JunoTamaño flexible de los elementos La abreviatura flex agrupa crecimiento, encogimiento y base. flex: 1 da columnas de igual ancho porque su base 0 hace que los elementos empiecen desde nada y crezcan de forma pareja. flex: 0 0 240px es tu sidebar fijo junto a un área principal con flex: 1, un diseño que vas a usar una y otra vez.
JunoTamaño flexible de los elementosflex-basis es el tamaño inicial antes de repartir el espacio, y gana sobre width en un elemento flex, así que flex: 1 (base 0) reparte el espacio de forma pareja mientras que flex: auto deja que el contenido influya en los anchos. Cuidado con el min-width: auto por defecto, que impide que un elemento se encoja por debajo de su contenido y desborda la fila hasta que configuras min-width: 0. Usa align-self para sacar un elemento de la alineación general, y cambia a grid en cuanto necesites filas y columnas alineadas.