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

Grid

docs.scrimba.com

Tienes una página con un encabezado en la parte superior, una barra lateral a la izquierda, un área de contenido principal y un pie de página. Podrías anidar un montón de contenedores y ajustar cada uno en su lugar, y funcionaría bien hasta el día en que necesites cambiar la disposición. CSS grid fue construido exactamente para este tipo de problema: distribuir una página en filas y columnas al mismo tiempo. Una vez que puedas describir un layout como un conjunto de tracks, la mayoría de los ajustes con wrappers y floats desaparece.

El contenedor grid

Conviertes cualquier elemento en un grid asignándole display: grid. Ese elemento se convierte en el contenedor grid, y sus hijos directos se convierten en elementos que se ajustan a un grid que defines. Por sí solo, display: grid no hace mucho, así que también le dices cuántas columnas y filas quieres y cuán grande debe ser cada una.

Describes las columnas con grid-template-columns y las filas con grid-template-rows. Cada valor en la lista es un track, y un track es una sola columna o fila:

css
.layout {
  display: grid;
  grid-template-columns: 200px 1fr;   /* dos columnas: una fija, luego el resto */
  grid-template-rows: 80px 400px;     /* dos filas: una corta, luego una alta */
}

Establecer display: grid en un elemento lo convierte en un contenedor grid, y sus hijos directos se convierten en elementos grid distribuidos en un grid que defines. Este es el equivalente bidimensional de flexbox, que distribuye elementos a lo largo de un solo eje a la vez. Flexbox pregunta "¿cómo deben esta fila (o columna) de elementos compartir el espacio?"; grid pregunta "¿dónde se sientan estos elementos en un conjunto de filas y columnas?".

Defines los tracks con grid-template-columns y grid-template-rows. Cada valor es un track, una columna o una fila, y los valores pueden mezclar unidades: longitudes fijas, porcentajes, o la flexible unidad fr que conoces en la siguiente sección.

css
.layout {
  display: grid;
  grid-template-columns: 200px 1fr;   /* barra lateral fija, columna principal flexible */
  grid-template-rows: auto 1fr auto;  /* encabezado se ajusta al contenido, principal llena, pie de página al contenido */
}

display: grid establece un contexto de formato grid en el elemento: se convierte en un contenedor grid, sus hijos directos se convierten en elementos grid, y las reglas de flujo normal que los gobernaban ya no se aplican. Los nodos de texto se envuelven en elementos anónimos, y propiedades como float y vertical-align dejan de tener efecto en los elementos, porque su colocación ahora es responsabilidad del grid.

La distinción de flexbox es la dimensionalidad, y es la primera decisión en acertar. Flexbox es unidimensional: distribuye elementos a lo largo de un eje principal y envuelve como efecto secundario, pero no alinea contenido en un grid coincidente en el eje transversal. Grid es bidimensional: define filas y columnas juntas, así que la posición de fila y columna de un elemento se establecen independientemente y los elementos se alinean en ambos ejes a la vez. Defines los tracks explícitos con grid-template-columns y grid-template-rows, cada valor produce un track:

css
.layout {
  display: grid;
  grid-template-columns: 200px 1fr;   /* dos tracks de columna explícitos */
  grid-template-rows: auto 1fr auto;  /* contenido, llenar, contenido */
}

La palabra clave auto dimensiona un track a su contenido; 1fr absorbe el espacio restante, que es el mecanismo en el que se basa la siguiente sección.

JunoEl contenedor grid Añade display: grid a un elemento y se convierte en un contenedor grid, con sus hijos directos sentados dentro como elementos. Luego dices cuántas columnas y filas quieres con grid-template-columns y grid-template-rows, un valor por track. Nada se alinea hasta que defines esos tracks, así que ese es siempre tu primer paso.
JunoEl contenedor grid Flexbox trabaja a lo largo de un eje a la vez; grid trabaja en filas y columnas juntas, por lo que los layouts de página se sienten más naturales en grid. Establece display: grid, luego enumera tus tracks en grid-template-columns y grid-template-rows. Recurre a grid cuando estés colocando cosas en una disposición bidimensional, y flexbox cuando estés alineando una fila o columna.
JunoEl contenedor griddisplay: grid crea un contexto de formato grid, así que los hijos dejan de obedecer el flujo normal y float y vertical-align dejan de importar silenciosamente en ellos. La verdadera separación de flexbox es la dimensionalidad: flex distribuye a lo largo de un eje, grid coloca en ambos a la vez. Elige grid cuando la posición de fila y columna son ambas significativas, flex cuando solo uno es.

Tracks flexibles

Las columnas de píxeles fijas están bien, pero la mayoría de los layouts quieren columnas que compartan el espacio de manera uniforme y crezcan con la pantalla. Para eso está la unidad fr. Un fr significa una porción del espacio restante, así que tres columnas de 1fr cada una toman un tercio del contenedor:

css
.gallery {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;   /* tres columnas iguales */
}

Escribir 1fr tres veces es tedioso, así que repeat() lo escribe por ti. Y gap establece el espacio entre los tracks, así que no necesitas usar márgenes en cada elemento:

css
.gallery {
  display: grid;
  grid-template-columns: repeat(3, 1fr);   /* las mismas tres columnas iguales */
  gap: 16px;                               /* espacio entre filas y columnas */
}

La unidad fr mide una porción del espacio libre en el contenedor después de que se restan los tamaños fijos y los gaps. Tres columnas a 1fr cada una obtienen un tercio igual; un par 2fr 1fr divide el espacio dos a uno. Como fr divide lo que queda, las columnas se mantienen proporcionales a medida que el contenedor crece o se encoge, lo que las longitudes fijas no pueden hacer.

Dos ayudantes hacen que las listas de tracks sean legibles. repeat(3, 1fr) se expande a 1fr 1fr 1fr, y gap establece los espacios entre tracks en una propiedad (con row-gap y column-gap cuando los quieres diferentes):

css
.gallery {
  display: grid;
  grid-template-columns: repeat(3, 1fr);   /* tres columnas iguales */
  gap: 16px;                               /* espacios de 16px, filas y columnas */
}

Los espacios se establecen con gap, no con márgenes en los elementos. Como gap solo se aplica entre tracks y nunca en los bordes exteriores, el grid se sienta al ras de su contenedor mientras los elementos se mantienen espaciados uniformemente.

La unidad fr es una longitud flexible: representa una fracción del espacio libre del contenedor, el espacio que queda después de que se resuelven los tamaños de track fijos, los tracks dimensionados al contenido y los gaps. Una lista de tracks 2fr 1fr 1fr da a la primera columna la mitad del espacio libre y a las otras dos un cuarto cada una. La sutileza es que fr distribuye espacio libre, no ancho total, así que un track que contiene contenido ancho puede pasar su porción fr a menos que lo limites, que es donde entra minmax() en la última sección.

repeat() es una forma compacta de escribir una secuencia de tracks: repeat(3, 1fr) es 1fr 1fr 1fr, y se compone, así que repeat(2, 200px 1fr) produce cuatro tracks. gap (el nombre moderno para grid-gap) establece espacios entre tracks solamente, nunca alrededor del exterior del grid, así que no compite con el padding del contenedor.

css
.gallery {
  display: grid;
  grid-template-columns: repeat(3, 1fr);   /* tres columnas iguales */
  gap: 16px 24px;                          /* 16px espacio de fila, 24px espacio de columna */
}

Nota el gap de dos valores: espacio de fila primero, luego espacio de columna. Un valor único se aplica a ambos.

JunoTracks flexibles Un fr es una porción del espacio restante, así que 1fr 1fr 1fr te da tres columnas iguales. Usa repeat(3, 1fr) para no escribir el mismo valor una y otra vez, y gap para el espacio entre tracks. Una vez que fr hizo clic para mí, dejé de recurrir a porcentajes que nunca se sumaban correctamente.
JunoTracks flexiblesfr divide el espacio libre en el contenedor, así que las columnas proporcionales se mantienen proporcionales a medida que la página cambia de tamaño. Confía en repeat() para mantener las listas de tracks cortas y gap para los espacios en lugar de márgenes por elemento. Recuerda que gap solo se sienta entre tracks, nunca en el borde exterior, que es generalmente exactamente lo que quieres.
JunoTracks flexiblesfr divide el espacio libre, no el ancho total, así que un track con contenido ancho puede desbordarse su porción hasta que lo limites con minmax(). repeat() se compone, así que repeat(2, 200px 1fr) son cuatro tracks. Y el gap de dos valores se lee espacio de fila primero, luego espacio de columna, lo que sorprende a quienes asumen que coincide con el atajo de las manecillas del reloj.

Colocación de elementos

Por defecto cada elemento cae en la siguiente celda libre, una por celda, en orden. Cuando quieres que un elemento ocupe más de una celda, lo dices con grid-column y grid-row. Las líneas entre tracks se numeran comenzando en 1, así que grid-column: 1 / 3 significa "empieza en la línea 1, termina en la línea 3", cubriendo dos columnas:

css
.featured {
  grid-column: 1 / 3;   /* abarca desde la línea de columna 1 a la línea 3, dos columnas de ancho */
}

Si no quieres contar líneas, span dice cuántas celdas cubrir desde donde el elemento cae:

css
.featured {
  grid-column: span 2;   /* cubre dos columnas, empezando donde se siente este elemento */
}

La colocación de grid se describe con líneas grid, las líneas numeradas que se sientan entre y alrededor de los tracks. Un grid de tres columnas tiene cuatro líneas de columna, 1 a través de 4. grid-column: 1 / 3 coloca un elemento de la línea 1 a la línea 3, así que abarca las primeras dos columnas; grid-row hace lo mismo verticalmente. La palabra clave span evita contar: grid-column: span 2 cubre dos columnas desde donde se coloca el elemento.

Para un layout de página completa, nombrar las regiones se lee mejor que contar líneas. grid-template-areas te permite dibujar el layout como un conjunto de celdas nombradas, luego asignar cada elemento a un nombre:

css
.page {
  display: grid;
  grid-template-columns: 200px 1fr;
  grid-template-areas:
    "sidebar header"
    "sidebar main";     /* la barra lateral abarca ambas filas al repetir su nombre */
}

.page > header { grid-area: header; }
.page > aside  { grid-area: sidebar; }
.page > main   { grid-area: main; }

La colocación se ejecuta en líneas grid, los límites numerados alrededor de cada track (un eje de n-tracks tiene n + 1 líneas). grid-column: 1 / 3 establece la línea de columna de inicio y fin, abarcando los tracks entre ellas; grid-column: span 2 establece un span sin fijar un inicio, dejando que el algoritmo de colocación automática elija dónde cae. Los números de línea negativos cuentan desde el final, así que grid-column: 1 / -1 siempre abarca el ancho completo independientemente del número de columnas, que es la forma duradera de escribir una fila de sangrado completo.

grid-template-areas nombra celdas para que coloques elementos por nombre en lugar de por número de línea. Cada cadena es una fila, cada token una celda, y repetir un token entre celdas hace que un elemento las abarque. El bloque formateado con espacios en blanco funciona también como un diagrama legible del layout:

css
.page {
  display: grid;
  grid-template-columns: 200px 1fr;
  grid-template-rows: auto 1fr;
  grid-template-areas:
    "sidebar header"
    "sidebar main";     /* la barra lateral ocupa ambas filas de la columna uno */
}

.page > aside { grid-area: sidebar; }

Dos reglas lo mantienen honrado: cada cadena de fila debe tener el mismo número de celdas, y las celdas para un nombre deben formar un rectángulo sólido, o la declaración es inválida e ignorada. Un token . marca una celda vacía que quieres dejar en blanco.

JunoColocación de elementos Los elementos llenan una celda cada uno por defecto, y haces que uno se extienda por celdas con grid-column o grid-row. Los números de línea comienzan en 1, así que grid-column: 1 / 3 cubre dos columnas, u usa span 2 si prefieres no contar. Eso es suficiente para construir la mayoría de los layouts antes de nombrar una sola área.
JunoColocación de elementos Coloca elementos con líneas grid: grid-column: 1 / 3 abarca dos columnas, y span 2 lo hace sin contar desde un inicio fijo. Para una página completa, grid-template-areas te permite nombrar las regiones y leer el layout de un vistazo, que supera el seguimiento manual de números de línea. Repite un nombre entre celdas y esa región las abarca.
JunoColocación de elementos Las líneas pueden ser negativas, así que grid-column: 1 / -1 abarca el ancho completo sin importar cuántas columnas haya, que es el truco de sangrado completo confiable. Con grid-template-areas, cada cadena de fila necesita celdas iguales y cada región nombrada debe ser un rectángulo sólido, o la declaración completa se descarta. Usa un token . para dejar una celda deliberadamente vacía.

Grids responsivos sin media queries

Una fila de tarjetas debe mostrar tres en una pantalla ancha, dos en una tablet, una en un teléfono. Puedes hacer eso con grid solo, sin breakpoints que escribir. El truco es una línea:

css
.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 16px;
}

Léelo de adentro hacia afuera. minmax(200px, 1fr) significa que cada columna es al menos 200px y como máximo una porción del espacio. auto-fit luego encaja tantas de esas columnas como el contenedor tenga espacio. Pantalla ancha, más columnas caben; pantalla estrecha, menos caben, y las tarjetas fluyen automáticamente.

El patrón que reordena tarjetas sin una sola media query es repeat(auto-fit, minmax(200px, 1fr)). Cada pieza hace un trabajo. minmax(200px, 1fr) define un track que nunca es más pequeño que 200px y nunca más grande que una porción fr. auto-fit repite ese track tantas veces como quepan en el ancho actual, así que el recuento de columnas responde al contenedor en lugar de a breakpoints fijos.

css
.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 16px;
}

El piso de 200px es tu control real: es el más estrecho que una tarjeta puede ser antes de que el grid caiga a menos columnas. Esto se empareja naturalmente con las técnicas fluidas en diseño responsivo, y generalmente reemplaza las media queries que de otro modo escribirías para un grid de tarjetas.

repeat(auto-fit, minmax(200px, 1fr)) es la expresión de grid responsivo canónica, y cada parte se gana su lugar. minmax(min, max) define un track con un límite inferior y superior: minmax(200px, 1fr) nunca se encoge por debajo de 200px y nunca crece más allá de una porción de espacio libre. El piso de 200px establece el umbral de reordenamiento, el ancho en el cual el grid gana o pierde una columna.

La elección entre auto-fit y auto-fill es la parte que vale la pena saber. Ambos calculan cuántos tracks minmax() caben en el contenedor. auto-fill mantiene los tracks vacíos restantes en el grid, así que una fila medio vacía de tarjetas se mantiene en el ancho de su columna. auto-fit colapsa esos tracks vacíos a ancho cero, así que los elementos presentes se expanden para llenar la fila:

css
.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));   /* los elementos se estiran para llenar */
  gap: 16px;
}

Mira un borde: minmax(200px, 1fr) puede desbordarse en un contenedor más estrecho que 200px más gaps, porque el piso es un mínimo duro. minmax(min(200px, 100%), 1fr) lo protege al permitir que el piso caiga al ancho del contenedor en pantallas muy pequeñas. Para dimensionar el piso de manera confiable entre dispositivos, unidades de dimensionamiento cubre cómo se resuelven las unidades de longitud.

JunoGrids responsivos sin media queriesrepeat(auto-fit, minmax(200px, 1fr)) hace que las tarjetas se reordenen por su cuenta, sin breakpoints necesarios. Cada columna es al menos 200px y como máximo una porción del espacio, y auto-fit empaca tantas como quepan. Cambia 200px y cambias cuántas tarjetas se sientan lado a lado.
JunoGrids responsivos sin media queries Una línea, repeat(auto-fit, minmax(200px, 1fr)), reemplaza un montón de media queries de grid de tarjetas. El piso de 200px es la palanca: decide cuán estrecha es una tarjeta antes de que el grid caiga una columna. Recurre a esto antes de escribir breakpoints para cualquier cosa que sea realmente un grid de tarjetas que se reordena.
JunoGrids responsivos sin media queriesauto-fit colapsa tracks vacíos para que los elementos presentes se estiren para llenar; auto-fill mantiene los tracks vacíos y deja espacios, que es toda la diferencia entre ellos. Mira el caso de desbordamiento: un piso 200px duro puede derramarse en contenedores muy estrechos, así que minmax(min(200px, 100%), 1fr) es el piso más seguro. El piso es lo que establece tus puntos de reordenamiento, así que elige con la tarjeta más pequeña sensata en mente.

Grids explícitos e implícitos

Todo hasta ahora define el grid explícito: los tracks que nombras en grid-template-columns y grid-template-rows. Cuando los elementos caen fuera de ese grid definido, el navegador crea tracks para sostenerlos, y aquellos forman el grid implícito. Añade un cuarto elemento a un grid explícito de tres columnas y una fila y comienza una segunda fila implícitamente creada. Los tracks implícitos se dimensionan auto por defecto, por lo que una fila implícita es solo tan alta como su contenido a menos que digas lo contrario.

grid-auto-rows establece el tamaño de esas filas implícitas (y grid-auto-columns las columnas implícitas), así que un grid de tarjetas cuyo recuento de filas no puedas predecir todavía obtiene filas uniformes:

css
.gallery {
  display: grid;
  grid-template-columns: repeat(3, 1fr);   /* explícito: tres columnas */
  grid-auto-rows: 240px;                   /* filas implícitas son 240px cada una */
  gap: 16px;
}

La alineación luego decide dónde se sientan los elementos y tracks dentro de sus celdas. justify-items alinea elementos a lo largo del eje de fila (inline) y align-items a lo largo del eje de columna (block), cada una aceptando start, end, center, o stretch (el predeterminado, que llena la celda). place-items es el atajo para ambos, eje block primero:

css
.gallery {
  place-items: center;   /* align-items y justify-items, ambos centrados */
}

minmax() también toma las palabras clave de contenido min-content y max-content: min-content es lo más pequeño que un track puede ser sin desbordarse (aproximadamente la palabra no rompible más larga), y max-content es el tamaño que el contenido quiere cuando nada lo fuerza a envolver. Un track como minmax(min-content, max-content) se dimensiona al contenido dentro de esos límites. Y subgrid permite que un grid anidado herede las líneas de track de su padre, así que las columnas de un grid hijo se alinean con el grid exterior en lugar de definir las suyas propias.

En la decisión de grid versus flex, la regla limpia es esta. Si estás distribuyendo contenido en un eje y permitiendo que se envuelva como consecuencia, usa flexbox: una barra de navegación, una fila de etiquetas, una barra de herramientas. Si estás colocando contenido en filas y columnas que deben alinearse en ambos ejes, usa grid: un shell de página, una galería de tarjetas, un formulario con etiquetas y campos alineados. Se componen bien, así que una celda de grid a menudo contiene un contenedor flex, y esa combinación cubre la mayoría de los layouts que construirás.

JunoGrids explícitos e implícitos Los tracks que declaras son el grid explícito; cualquier cosa que el navegador agregue para sostener elementos que se desbordan es el grid implícito, y esos tracks extras son dimensionados auto hasta que grid-auto-rows o grid-auto-columns dice lo contrario. La alineación vive en justify-items y align-items, con place-items como el atajo y stretch como el predeterminado. La decisión es un eje con envolvimiento significa flexbox, dos ejes que deben alinearse significa grid, y se anidan felizmente.