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

Flexbox

docs.scrimba.com

Quieres tres botones sentados en una fila, espaciados uniformemente, todos con la misma altura, y centrados verticalmente sin importar cuánto texto tenga cada uno. En los viejos tiempos esto significaba floats, clearfixes y mucha adivinanza. Flexbox es la herramienta construida para exactamente esto: le dices a un contenedor que distribuya sus hijos en una línea, y luego los ajustas en dos ejes hasta que se sienten donde quieres. La mayoría de los diseños cotidianos que ves en la web, barras de navegación, barras de herramientas, filas de tarjetas, tiene un contenedor flex debajo.

El contenedor flex

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

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

Los elementos se distribuyen en dos direcciones. El eje principal va de izquierda a derecha, la forma en que se alinean los elementos. El eje transversal va de arriba a abajo, a través de la fila. Dirigirás elementos a lo largo de ambos, así que ayuda visualizarlos ahora: el eje principal es la línea en la que se sientan los elementos, el eje transversal es la dirección a través de él.

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

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

Todo el modelo funciona en dos ejes. El eje principal es la dirección en la que fluyen los elementos, una fila por defecto, así que de izquierda a derecha. El eje transversal es perpendicular a él, corriendo de arriba a abajo. Cada propiedad de alineación que encuentres funciona en uno u otro eje, así que mantener los dos derechos es lo que hace que el resto encaje en su lugar.

display: flex le da a un elemento un contexto de formato flex: sus hijos directos se convierten en elementos flex y se distribuyen por el algoritmo flex en lugar del flujo normal. Solo los hijos directos participan; las ejecuciones de texto y los descendientes anidados se manejan debajo de ellos. Este es el mismo tipo de límite que detiene el colapso de márgenes, que es una razón por la que los diseños flex se comportan de manera más predecible que la era de floats-and-clear que reemplazaron.

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

Dos ejes rigen todo. El eje principal se establece por flex-direction (una fila por defecto, así que 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 volteas 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 lo mantiene coherente cuando la dirección cambia.

css
.nav {
  display: flex;
}

Una única declaración, y los hijos de cualquier bloque dejan de apilarse de arriba a abajo y comienzan a sentarse en una fila. Todo lo demás en este capítulo trata sobre dirigir esos elementos una vez que están en el 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 en dos direcciones: el eje principal es la línea en la que se sientan, el eje transversal corre a través de él, y empujarás elementos a lo largo de ambos.
JunoEl contenedor flexdisplay: flex hace que un contenedor distribuya sus hijos directos como una fila de elementos flex. Solo los hijos directos participan, no nada anidado más profundamente. Mantén los dos ejes claros en tu cabeza: el eje principal es la dirección de flujo, el eje transversal es perpendicular, y cada propiedad de alineación funciona en uno u otro.
JunoEl contenedor flexdisplay: flex inicia un contexto de formato flex, así que los hijos directos se distribuyen por 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 rastrea el eje principal y align-items el eje transversal. Voltea flex-direction a column e esos dos intercambian hacia dónde empujan.

Alineación a lo largo de los ejes

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

css
.nav {
  display: flex;
  justify-content: space-between;   /* empuja elementos aparte a lo largo de la fila */
  align-items: center;              /* alinéalos en el medio vertical */
}

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

Para centrar algo en ambas formas, el movimiento que todos aprenden primero: establece ambos 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 manejan la alineación, una por eje. justify-content distribuye elementos a lo largo del eje principal, y align-items los posiciona en el eje transversal. Porque poseen diferentes ejes, nunca se pelean, apuntan en direcciones perpendiculares.

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

Para justify-content, los valores que vale la pena saber son flex-start, center, flex-end, space-between (espacios iguales entre elementos, alineados con 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 predeterminado es stretch, que hace que cada elemento llene la altura del contenedor, y esa es la razón por la que una fila de tarjetas sale con la misma altura incluso cuando su contenido difiere. Establece align-items: center y se encogerán de vuelta a su altura de contenido y se sentarán en el medio en lugar de eso.

El centrado en ambos ejes es el par de propiedades que hace que flexbox sea famoso:

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

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

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

La distinción que confunde a la gente es que justify-content solo tiene algo que ver cuando hay espacio restante en el eje principal. Distribuye espacio libre, así que si los elementos ya llenan el contenedor (u lo desbordan), space-between y center se ven idénticos porque no hay nada que distribuir. align-items, por el contrario, posiciona cada elemento independientemente dentro del tamaño transversal del contenedor, y su valor inicial es stretch: elementos sin un tamaño fijo del eje transversal crecen para llenar el contenedor. La fila de tarjetas de altura igual es align-items: stretch haciendo su trabajo predeterminado. Anúlalo por elemento con align-self, cubierto en la sección de dimensionamiento a continuación.

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

Dos elementos y una min-height en el contenedor, ambos establecidos en center, y has resuelto el problema de centrado que tardó una generación de desarrolladores en posicionamiento absoluto y márgenes negativos para falsificar.

JunoAlineación a lo largo de los ejesjustify-content espacía elementos a lo largo del eje principal, align-items los mueve a lo largo del eje transversal. Los valores a recordar para el primero son center, space-between, y flex-start. Establece ambos en center y lo que sea que esté adentro se sienta justo en el medio, que es el movimiento de diseño que usarás una y otra vez.
JunoAlineación a lo largo de los ejes Una propiedad por eje: justify-content en el eje principal, align-items en el transversal. El predeterminado align-items: stretch es por qué una fila de tarjetas sale con la misma altura sin que lo pidas. Y ambos establecidos en center es el movimiento de centrado que vale la pena memorizar.
JunoAlineación a lo largo de los ejesjustify-content distribuye el espacio restante del eje principal, así que si los elementos ya llenan la fila no hace nada, lo que explica muchos momentos de "por qué esto no se centra". align-items posiciona cada elemento en el eje transversal y el predeterminado es stretch, dándote filas de altura igual gratis. Voltea flex-direction y recuerda que ambas propiedades intercambian el eje en el que actúan.

Dirección y ajuste

Por defecto, un contenedor flex distribuye elementos en una fila. Cambia eso con flex-direction. Establécela a column y los elementos se apilan de arriba a abajo en lugar de sentarse uno al lado del otro.

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

Cuando los elementos en una fila se quedan sin espacio, se aplastan cada vez más delgados. Para dejarlos caer en una nueva línea en lugar de eso, añade flex-wrap: wrap.

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

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

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

flex-direction establece el eje principal. El predeterminado row corre de izquierda a derecha; column gira el eje principal a vertical, así que los elementos se apilan de arriba a abajo e, importante, justify-content ahora controla el espaciado vertical mientras que align-items controla el horizontal. También hay row-reverse y column-reverse si necesitas el orden volteado.

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

Por defecto, una línea flex nunca se rompe: los elementos se encogen para caber en lugar de ajustarse. Establece flex-wrap: wrap y los elementos que no pueden caber se mueven a una nueva línea, que es lo que hace posible una cuadrícula de tarjetas receptiva sin consultas de medios.

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 final del último hijo.

flex-direction define el eje principal, y cada propiedad dependiente del eje la sigue. row (el predeterminado) hace que el eje principal sea horizontal; column lo hace vertical y reasigna silenciosamente justify-content al espaciado vertical y align-items al horizontal. Las variantes -reverse voltean la dirección del eje principal, pero nota que solo reordenan visualmente: el orden del DOM no cambia, así que el orden del teclado y el del lector de pantalla aún siguen la fuente, que es una consideración real de accesibilidad cuando llegas a 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 todos los elementos a una línea y distribuye cualquier escasez encogiéndolos; con él, los elementos que desbordan el tamaño principal se rompen en nuevas líneas, y el contenedor se vuelve multi-línea. Una vez que el ajuste está activado, align-content (distinto de align-items) rige cómo las líneas se espacían en el eje transversal. gap establece el espacio entre elementos y, cuando se ajusta, entre líneas, y es la herramienta correcta: a diferencia de márgenes no colapsa nada, no añade espacio de borde, 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 */
}

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

JunoDirección y ajusteflex-direction: column apila elementos verticalmente en lugar de en una fila. flex-wrap: wrap permite que los elementos caigan a una nueva línea cuando se quedan sin espacio, en lugar de ser aplastados. Y gap pone espacio uniforme entre elementos sin añadir ninguno en los bordes, así que alcánzalo antes que márgenes.
JunoDirección y ajusteflex-direction establece el eje principal, y cambiar a column significa que justify-content ahora espacía verticalmente, que sorprende a la gente una vez. flex-wrap: wrap es lo que hace que una fila de tarjetas refluya sin consultas de medios. Usa gap para el espaciado así nunca persigues un margen extraño en el último elemento.
JunoDirección y ajusteflex-direction define el eje principal y cada propiedad basada en eje la sigue, mientras que los valores -reverse reordenan visualmente pero dejan el orden del DOM y del enfoque solo, así úsalos con cuidado. flex-wrap convierte un contenedor en multi-línea y entrega el espaciado de líneas a align-content. Cuando los elementos ajustados necesitan alinearse en columnas reales, eso es grid, no flexbox.

Dimensionamiento flexible de elementos

El punto de flexbox es que los elementos pueden flexionarse, crecer o encoger para compartir el espacio. El atajo que usarás más es flex: 1 en un elemento, que le dice que crezca y tome una parte igual de cualquier 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 otras. Ese número único es cómo los elementos dividen el espacio restante 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. Raramente los estableces uno por uno al principio, el atajo cubre los casos comunes, pero ayuda saber que están ahí.

Tres propiedades deciden cómo los elementos comparten espacio. flex-grow establece cuánto crece un elemento para llenar el espacio restante (0 significa no crecer). flex-shrink establece cuánto cede cuando el espacio es escaso (1, el predeterminado, significa que puede encogerse). flex-basis establece el tamaño inicial del elemento antes de crecer o encoger, y el predeterminado es auto, lo que significa "usa el contenido o el ancho".

El atajo flex agrupa los tres, y los valores que realmente escribes son pocos:

css
.card {
  flex: 1;   /* crecer 1, encoger 1, base 0: columnas de ancho igual */
}

.sidebar {
  flex: 0 0 240px;   /* no crecer, no encoger, mantenerse en 240px */
}

flex: 1 es la herramienta de trabajo: hace que los elementos dividan la fila en partes iguales sin importar su contenido, porque la base 0 significa que comienzan de nada y crecen solo por su factor de crecimiento. flex: 0 0 240px es la barra lateral de ancho fijo al lado de un área principal flex: 1, un diseño que construirás constantemente.

El dimensionamiento de 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 predeterminado auto se remite al width del elemento (o tamaño de 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 distribuye en proporción a flex-grow de cada elemento. Si hay un déficit, se devuelve en proporción a 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 de contenido y dividen espacio por factor de crecimiento */
}

La parte sutil es flex-basis versus width, porque interactúan. flex-basis: 0 (como en flex: 1) hace que los elementos ignoren su contenido y dividan espacio solo por factor de crecimiento, dando verdaderas columnas iguales. flex-basis: auto (como en flex: auto, o un width simple) hace que cada elemento comience en 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 ellos es realmente elegir si el contenido debe influir en los anchos finales.

Dos notas de producción. Primero, flex-basis vence a width cuando ambos se establecen, así que una vez que un elemento es un elemento flex, prefiere expresar su tamaño a través de flex. Segundo, la trampa de desbordamiento: un elemento flex tiene un predeterminado min-width: auto, lo que significa que se niega a encoger por debajo del tamaño intrínseco de su contenido, así que una palabra larga o un hijo desbordante puede romper toda la fila. La solución es min-width: 0 en el elemento que debería poder encoger.

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

align-self anula align-items para un único elemento, así que un elemento puede sentarse en flex-start mientras el resto se centra. Y la llamada de herramientas: alcanza para flexbox para diseños unidimensionales, una barra de navegación, una barra de herramientas, una fila o columna única de elementos. Cuando necesitas filas alineadas y columnas a la vez, cuadrícula CSS es la herramienta correcta. Si no estás seguro de cómo se resuelven los anchos debajo de todo esto, unidades de dimensionamiento cubre cómo se comportan los porcentajes y otras unidades aquí.

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

Una barra lateral fija al lado de una columna principal flexible, tres líneas de intención. Este patrón, más la barra de navegación alineada de antes, cubre una gran parte de los diseños que construirás.

JunoDimensionamiento flexible de 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 con el mismo ancho. Sube una a flex: 2 y toma el doble del espacio. Ese número único es cómo los elementos flex dividen el espacio entre ellos.
JunoDimensionamiento flexible de elementos El atajo flex agrupa crecer, encoger y base. flex: 1 da columnas de ancho igual porque su base 0 hace que los elementos comiencen de nada y crezcan uniformemente. flex: 0 0 240px es tu barra lateral fija al lado de un área principal flex: 1, un diseño que alcanzarás una y otra vez.
JunoDimensionamiento flexible de elementosflex-basis es el tamaño inicial antes de que se comparta espacio, y vence a width en un elemento flex, así que flex: 1 (base 0) divide espacio uniformemente mientras que flex: auto permite que el contenido influya en los anchos. Vigila el predeterminado min-width: auto, que detiene que un elemento se encoja por debajo de su contenido y desbordar la fila hasta que establezca min-width: 0. Usa align-self para sacar un elemento de la alineación, y cambia a grid en el momento en que necesites filas y columnas alineadas.