Ir al contenido
wannacode

Flexbox: fila y columna

En resumen: Flexbox coloca los elementos en una fila o en una columna a lo largo del eje principal, los alinea en el eje transversal y reparte el espacio libre con flex-grow.

Problema

La cabecera en tres líneas

La nueva cabecera de la tienda debería ser una sola línea: el logo a la izquierda, el menú a su lado y el carrito a la derecha. En una computadora son tres líneas, una debajo de otra.

HTML, CSS, JS

El CSS no tiene ningún error. <nav> es un elemento de bloque, y los elementos de bloque se apilan, cada uno en una línea entera. Los enlaces son elementos en línea y comparten línea con el texto que los rodea. Así que el logo está en la primera línea, el menú en la segunda y el carrito en la tercera.

La idea

Contenedor y elementos

Los hijos de la cabecera necesitan otra forma de colocarse. Es display: flex en el padre:

header {
display: flex;
}
  • El elemento con display: flex es un contenedor flex. Sus hijos (solo los directos) son elementos flex.
  • Los elementos se colocan uno al lado del otro a lo largo del eje principal. Por defecto va de izquierda a derecha. flex-direction: column lo gira de arriba abajo.
  • En ángulo recto con él está el eje transversal.

La disposición se define en el contenedor, no en los hijos:

  • justify-content reparte a lo largo del eje principal: flex-start (al principio), center, flex-end, space-between (el primero al principio, el último al final, el espacio entre ellos).
  • align-items alinea a lo largo del eje transversal: stretch (el valor por defecto, todos tan altos como la línea), center, flex-start, flex-end.
  • gap pone el mismo espacio entre los elementos, y nada antes del primero ni después del último.

Un elemento puede ser a la vez elemento flex y contenedor flex. nav { display: flex; gap: 12px; } coloca los enlaces del menú, y el propio menú es un elemento de la cabecera.

Pruébalo

Logo a la izquierda, carrito a la derecha

Pon la cabecera en una sola línea: el logo en el borde izquierdo, el carrito en el derecho y el menú entre ellos. Usa justify-content. La comprobación mide en cuántas filas están los hijos de <header>.

HTML, CSS, JS

Pruébalo

Encuentra el error

La cabecera está en fila, pero el carrito no se va a la derecha. ¿Por qué?

Elige la línea con el error.

La idea

El espacio libre

La cabecera tiene también un campo de búsqueda. Debe ocupar todo el espacio entre el logo y el carrito, sea cual sea el ancho de la pantalla. Aquí ayudan tres propiedades del elemento flex:

  • flex-basis es la base: el ancho del elemento antes de repartir nada. Por defecto es auto: su width, o tan ancho como su contenido.
  • flex-grow dice cuántas partes del espacio libre toma el elemento. Por defecto es 0: no crece.
  • flex-shrink dice cuánto se encoge si no hay espacio suficiente. Por defecto es 1.

El navegador lo calcula así:

  1. Coloca cada elemento con su base.
  2. El espacio libre es el ancho del contenedor menos las bases y los gap.
  3. Reparte el espacio libre según flex-grow, y cada elemento crece su parte.

La propiedad flex define las tres a la vez. flex: 1 es flex-grow: 1, flex-shrink: 1 y flex-basis: 0%: el elemento crece y su base es cero. Por eso tres elementos con flex: 1 quedan igual de anchos, tengan el texto que tengan.

Míralo

Mira cómo se reparte el espacio

Una barra de 600px con tres elementos. Fíjate en la suma de arriba y en el espacio libre verde.

.bar {
display: flex;
width: 600px;
gap: 20px;
}
.logo { flex-basis: 120px; }
.search { flex-basis: 100px; flex-grow: 2; }
.cart { flex-basis: 100px; flex-grow: 1; }
Paso a paso, en palabras
  1. .bar es un contenedor flex de 600px de ancho. Sus hijos son elementos flex: se colocan en fila a lo largo del eje principal, de izquierda a derecha.
  2. Primero cada elemento recibe su flex-basis: 120, 100 y 100px. Es su ancho antes de repartir nada.
  3. Entre tres elementos hay dos gap de 20px. Ocupado: 120 + 100 + 100 + 2 × 20 = 360px.
  4. Lo que sobra es el espacio libre: 600 − 360 = 240px.
  5. flex-grow dice cuántas partes toma cada elemento: logo 0, search 2, cart 1, tres en total. Una parte son 240 : 3 = 80px.
  6. Cada elemento crece según sus partes: search 160px, cart 80px y logo se queda igual. Los anchos son 120, 260 y 180px.
  7. 120 + 20 + 260 + 20 + 180 = 600: la fila está llena. El navegador da exactamente estos anchos. search no es el doble de ancho que cart: solo el espacio libre se reparte 2 : 1.

search tiene flex-grow: 2 y cart tiene 1, pero search no es el doble de ancho: 260 frente a 180. Solo se reparte el espacio libre, y las bases se quedan. Por eso, si quieres columnas iguales, la base tiene que ser cero: flex: 1.

Pruébalo

La búsqueda toma el resto

El logo mide 120px, el carrito 110px y la cabecera llega hasta 640px. Haz que el campo de búsqueda ocupe todo el espacio entre ellos. La comprobación mide su ancho en píxeles: 640 − 2 × 16 (padding) − 120 − 110 − 2 × 16 (gap) = 346px.

HTML, CSS, JS

Pruébalo

Uno a la derecha

A veces quieres el logo y el menú a la izquierda y solo el carrito a la derecha. space-between no sirve: el menú se iría al centro. Hay una propiedad del propio elemento: un margin con el valor auto toma todo el espacio libre de su lado y empuja el elemento.

header { display: flex; gap: 16px; }
.cart { margin-left: ; }

Pruébalo

Una línea nueva cuando no caben

Por defecto un contenedor flex mantiene todos los elementos en una línea (flex-wrap: nowrap). Si no caben, los encoge, y cuando ya no puede, la línea se sale de la pantalla. Con flex-wrap: wrap los elementos que no caben pasan a una línea nueva.

En un teléfono (360px) los cuatro productos están apretados en una línea y la página se desplaza hacia los lados. Ponlos de dos en dos, cada uno de al menos 150px, y los dos de una línea igual de anchos. La comprobación cuenta las líneas y las columnas y mide el ancho de las tarjetas.

HTML, CSS, JS

La idea

El nombre que no se encoge

En el carrito el nombre del producto está junto a la imagen, y a su lado van la cantidad y el precio. El nombre es largo. Queremos cortarlo con «…» en una línea: white-space: nowrap, overflow: hidden y text-overflow: ellipsis. El bloque con el nombre tiene flex: 1. Sin embargo, en un teléfono la línea se sale de la pantalla y el precio queda apretado:

HTML, CSS, JS

La causa es una sola regla. Un elemento flex no se encoge por debajo de su contenido más estrecho: min-width vale auto por defecto, no 0. Para .info el contenido más estrecho es el nombre entero en una línea. min-width: 0 en el elemento flex quita ese límite. Entonces .info se encoge, y el encabezado de dentro corta el texto.

Alguien añadió min-width: 0, pero el nombre sigue sin cortarse. ¿Qué línea está mal?

Más precisamente, para curiosos

Encogerse. Si las bases y los gap suman más que el contenedor, el espacio libre es negativo y los elementos se encogen. El reparto no depende solo de flex-shrink, sino de flex-shrink × la base: un elemento ancho se encoge más. La barra de la escena, pero de 280px: 120 + 100 + 100 + 40 = 360, faltan 80px. Los pesos son 120, 100 y 100. logo pierde 80 × 120 : 320 = 30px y los otros 25px cada uno: 90, 75 y 75px. Un elemento con flex-shrink: 0 no se encoge.

Los valores de flex. flex: 1 es 1 1 0%. flex: auto es 1 1 auto: crece, pero desde el ancho de su contenido. flex: none es 0 0 auto: ni crece ni se encoge. flex: 0 0 64px es un elemento de exactamente 64px.

Lo que no se encoge. Las imágenes y los campos tienen un ancho propio, y min-width: auto les impide encogerse. Por eso en el carrito el precio (<strong>) queda apretado y la imagen no.

Otro camino. overflow: hidden en el propio elemento flex también quita el límite: un elemento que recorta su contenido puede encogerse hasta 0.

Un elemento distinto. align-self alinea un solo elemento en el eje transversal. order cambia su lugar en la pantalla pero no en el árbol: el teclado y el lector de pantalla siguen el árbol. Por eso no movemos con order lo que la gente pulsa.

Líneas con wrap. align-content coloca las propias líneas en el eje transversal cuando el contenedor es más alto que ellas. display: inline-flex crea un contenedor que va en el texto como una palabra.

Ejercicio

Una línea del carrito

Coloca una línea del carrito en un teléfono (360px): la imagen, el nombre, la cantidad y el precio en fila, centrados en vertical, con 12px entre ellos. La imagen sigue en 64px, la cantidad en 56px y el precio en 72px. El nombre toma el resto del espacio (aquí 108px) y va en una línea, y si es largo, se corta con «…». La página no se desplaza hacia los lados.

HTML, CSS, JS

Test

Ponte a prueba

1. Quieres tres productos uno al lado del otro. ¿En qué elemento escribes display: flex?
2. Una barra de 500px con gap: 20px tiene dos elementos con flex-basis: 100px. El primero tiene flex-grow: 1 y el segundo flex-grow: 3. ¿Cuánto miden de ancho?
3. El contenedor tiene flex-direction: column. ¿A lo largo de qué eje actúa justify-content?
4. El nombre de .info { flex: 1 } tiene white-space: nowrap y text-overflow: ellipsis, pero no se corta y la fila se sale de la pantalla. ¿Qué falta?

Creado por Ivo Gergov como parte de la campaña de Evo Tech por una educación accesible en programación ·