2 puntos por GN⁺ 2024-08-17 | 1 comentarios | Compartir por WhatsApp
  • CSS Grid ha sido ampliamente compatible en los principales navegadores desde marzo de 2017, pero grid-template-areas todavía se usa menos, aunque permite expresar el layout visualmente dentro del CSS sin calcular números de línea
  • grid-template-areas funciona colocando nombres de áreas como cadenas y vinculándolos con grid-area en los elementos hijos; los nombres repetidos deben formar obligatoriamente un área rectangular
  • Las líneas de grid con nombre consisten en asignar nombres a las líneas, como content-start / content-end, y el patrón *-start y *-end permite que el navegador los use como áreas implícitas
  • En casos como tarjetas invertidas, headers responsivos, layouts editoriales, publicaciones estilo Threads, tarjetas superpuestas y layouts condicionales con :has(), se pueden gestionar variantes de distribución cambiando solo las cadenas de áreas del contenedor padre
  • Chrome, Safari y Firefox ofrecen DevTools para áreas de Grid, y Firefox resulta especialmente útil por mostrar nombres de áreas y ofrecer autocompletado de nombres de línea posibles al editar grid-area

Hacer que los layouts sean más legibles con grid-template-areas

  • En CSS Grid, una forma común de posicionar elementos ha sido indicar directamente números de línea, como grid-column: 1 / 3
  • Los números de línea no se ven hasta revisarlos en DevTools, y en layouts con columnas y filas es difícil calcular mentalmente los números correctos
  • grid-template-areas asigna nombres a cada celda, así que el propio CSS se ve como un mapa del layout
.page {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-areas: "item1 item2";
  gap: 1rem;
}

.item-1 {
  grid-area: item1;
}

.item-2 {
  grid-area: item2;
}
  • Los elementos hijos se mapean a áreas con nombre usando grid-area
  • En el ejemplo de tarjetas, una definición como "featured featured article" permite que el área featured ocupe 2 columnas y article ocupe 1

Sintaxis y reglas que hay que respetar sí o sí

  • grid-template-areas acepta una o más cadenas de áreas
    • Una sola cadena crea un layout unidimensional con solo columnas
    • Varias cadenas forman un layout multidimensional con filas y columnas
  • Cuando se usan varias cadenas, escribirlas en líneas separadas hace que el layout sea más fácil de leer
.element {
  display: grid;
  grid-template-columns: 200px 1fr;
  grid-template-areas:
    "aside main"
    "footer footer";
}
  • Cada cadena representa una fila del grid, y puede pensarse como una tabla
  • Las áreas definidas con el mismo nombre deben ser rectangulares dentro del código
/* invalid */
.layout {
  grid-template-areas:
    "header header"
    "sidebar main"
    "header footer";
}

/* valid */
.layout {
  grid-template-areas:
    "header header"
    "sidebar main"
    "sidebar footer";
}
  • Todas las filas deben tener la misma cantidad de tokens de área, y aunque un área no se use, la celda en sí debe definirse
  • Las celdas vacías pueden representarse con un punto o con varios puntos
.element {
  grid-template-areas:
    "aside main"
    "... footer";
}
  • El punto es un null cell token de la especificación de CSS Grid, y representa una celda vacía del grid

Relación entre líneas de grid con nombre y áreas

  • En CSS Grid siempre hay una línea más que la cantidad de columnas
    • Si hay 3 columnas, se crean 4 líneas de grid
  • Las líneas de grid con nombre consisten en asignar nombres únicos a las líneas en lugar de usar solo números
.layout {
  grid-template-columns:
    [full-start] 1fr
    [content-start] 2fr
    [content-end] 1fr [full-end];
}

.item {
  grid-column: content-start / content-end;
}
  • Aunque pongas nombre a las líneas, las líneas numéricas siguen pudiéndose usar
  • El tamaño de pista (track size) se refiere al tamaño de una columna o fila, y valores como 1fr 1fr son tamaños de pista
  • En las líneas con nombre, se nombran las líneas alrededor de las pistas
.layout {
  display: grid;
  grid-template-columns:
    [aside-start] 200px [aside-end main-start] 1fr [main-end];
}
  • Una misma línea puede compartir varios nombres; en el ejemplo de arriba, aside-end y main-start son la misma línea
  • Si defines nombres como aside-start y aside-end, el navegador puede permitir usos como grid-column: aside mediante nombres de línea implícitos
  • No hace falta nombrar todas las líneas; se pueden nombrar selectivamente solo las importantes
  • Al posicionar elementos, se pueden mezclar números y nombres, como en grid-column: 1 / content-end

Gestionar variantes de layout con las cadenas de áreas del contenedor padre

  • Al usar grid-template-areas, puedes mantener los nombres grid-area de los hijos y cambiar todo el layout modificando solo las cadenas de áreas del contenedor padre
.aside {
  grid-area: aside;
}

.main {
  grid-area: main;
}

.footer {
  grid-area: footer;
}
  • Si mantienes los mismos nombres aside, main y footer, basta con cambiar la cadena de grid-template-areas para actualizar automáticamente toda la distribución
  • El control del layout queda centralizado en la definición de áreas del padre, lo que facilita los ajustes

Invertir la orientación de una tarjeta

  • Con Flexbox, es fácil invertir la dirección de una tarjeta con flex-direction: row-reverse
  • En CSS Grid, si usas números de línea, al cambiar la dirección tienes que modificar tanto la definición de columnas como los valores grid-column de cada hijo
  • Con áreas con nombre, basta con asignar imagen y contenido a áreas y luego cambiar solo el orden de esas áreas en el contenedor padre
.card {
  display: grid;
  grid-template-columns: 150px 1fr;
  grid-template-areas: "thumb content";
}

.card__thumb {
  grid-area: thumb;
}

.card__content {
  grid-area: content;
}

.card--flip {
  grid-template-columns: 1fr 150px;
  grid-template-areas: "content thumb";
}
  • El mismo layout también puede expresarse con la propiedad abreviada grid-template
.card--flip {
  grid-template: "content image" / 1fr 150px;
}
  • La propiedad abreviada es opcional, y también es válido preferir la versión larga por ser más legible

Layout de header responsivo

  • Un header con logo, navegación y acciones puede comenzar con 3 columnas del mismo tamaño
  • Si usas números de línea, tienes que asignar grid-column a .logo, .nav y .actions por separado
  • Si usas nombres de área, puedes mapear cada hijo a logo, nav y actions, y luego cambiar solo grid-template-areas del padre según el viewport
.header {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  grid-template-areas: "logo nav actions";
}

.logo {
  grid-area: logo;
}

.nav {
  grid-area: nav;
}

.actions {
  grid-area: actions;
}
  • En tamaños pequeños, el logo y las acciones pueden ir en la primera fila y la navegación puede ocupar todo el ancho
.header {
  grid-template-areas:
    "logo logo actions"
    "nav nav nav";
}
  • A partir de 380px, el logo puede quedar a la izquierda y la navegación y acciones a la derecha
@media (min-width: 380px) {
  .header {
    grid-template-areas:
      "logo nav nav"
      "logo actions actions";
  }

  .nav {
    justify-self: end;
  }
}
  • A partir de 900px, puede volver a una distribución en una sola fila
@media (min-width: 900px) {
  .header {
    grid-template-areas: "logo nav actions";
  }
}
  • Las cadenas de áreas funcionan como un mapeo que muestra directamente la distribución de la UI dentro del CSS

Ejemplo de layout editorial

  • Una sección con título, texto e imagen puede cambiar fácilmente su distribución según el tamaño del viewport usando grid-template-areas
.section {
  display: grid;
  grid-template-areas:
    ". title title"
    "thumb content content";
  gap: 1rem;
}
  • El punto a la izquierda del título representa espacio vacío y es un null cell token
  • En el ejemplo de una sección estilo time.com, se usan las áreas feature, secondary y most-read, junto con columnas vacías a ambos lados
.featured-section {
  display: grid;
  grid-template-areas:
    ". feature most-read ."
    ". secondary most-read .";
  grid-template-columns: 1fr minmax(auto, 57.313rem) minmax(12rem, 18.75rem) 1fr;
  grid-template-rows: minmax(auto, 25rem) 1fr;
}
  • Las columnas vacías de ambos lados suelen servir como separación horizontal
  • En la versión responsiva, en pantallas pequeñas se apilan verticalmente feature, secondary y most-read, y a partir de 500px y 900px se cambian las definiciones de columnas y áreas
  • grid-template-rows puede sustituirse por la definición de áreas, así que no es estrictamente necesario

Componente de publicación estilo Threads

  • Al revisar el CSS de Threads app by Meta, se puede ver un caso de uso de CSS Grid en un componente de publicación
  • El ejemplo original posiciona elementos con grid-template-columns, grid-template-rows y números de línea
.postBody {
  grid-column-start: 2;
  grid-row-start: 2;
  grid-row-end: span 3;
}
  • Varias variantes de publicación pueden expresarse más fácilmente con grid-template-areas
.post {
  grid-template-areas:
    "avatar header"
    "avatar body"
    ". body"
    ". footer";
}

.post--reply {
  grid-template-rows: 40px max-content max-content;
  grid-template-areas:
    "avatar header"
    "body body"
    "body body"
    "footer footer";
}

.post--nested {
  grid-template-areas:
    "avatar header"
    "avatar body"
    "line body"
    "footer footer";
}
  • Solo con mirar las cadenas de áreas se pueden distinguir la variante base, la respuesta y la publicación anidada

Elementos superpuestos y nombres de área

  • En grid-template-areas, los nombres repetidos deben formar rectángulos, así que repetir el mismo nombre con una forma no rectangular no es válido
.layout {
  display: grid;
  grid-template-columns: 1fr 1fr fr;
  grid-template-areas:
    "card tag tag"
    "title title card";
}
  • En el ejemplo de arriba, card no forma un rectángulo, así que es invalid
  • En tarjetas superpuestas, se pueden definir nombres nuevos como thumb-1 y thumb-2, y luego usarlos en grid-column y grid-row
.card {
  display: grid;
  grid-template-columns: auto auto 1fr;
  grid-template-rows: auto auto;
  grid-template-areas:
    "thumb-1 tag"
    "title thumb-2";
}

.thumb {
  grid-column: thumb-1 / thumb-2;
  grid-row: thumb-1 / thumb-2;
}
  • La etiqueta y el título pueden colocarse con grid-area y alinearse con align-self y justify-self
  • Si hace falta, hay que gestionar el orden de apilamiento de los hijos, aunque en el ejemplo basta con el orden del código fuente
  • Este ejemplo de superposición está inspirado en la página Oddbird’s Cascading Layouts

:has() y layouts condicionales

  • Al combinar el selector CSS :has() con áreas de Grid, se puede cambiar el layout según exista o no cierto elemento
  • Se pueden aplicar definiciones de áreas distintas dentro de <figure> según haya o no figcaption
figure {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  grid-template-areas: "img img img";
  gap: 0.5rem;
}

img {
  grid-area: img;
}

figcaption {
  grid-area: caption;
}

.card:has(figcaption) {
  grid-template-areas:
    "img img caption"
    "img img .";
}

Compatibilidad con direcciones LTR/RTL en entornos multilingües

  • CSS Grid ajusta el layout según si la página está en dirección LTR o RTL
  • Las áreas de grid con nombre también siguen la dirección de la página, así que el layout se invierte en una configuración RTL
  • Para escribir layouts RTL, puede consultarse la guía RTL Styling 101

Diferencias en el soporte de DevTools

  • Chrome, Safari y Firefox ofrecen DevTools para áreas de Grid
  • Chrome
    • Coloca los nombres de las áreas en la esquina superior izquierda, lo que puede hacer que se vean superpuestos
    • La superposición de color puede cambiar la forma en que se percibe el diseño
  • Safari
    • El contorno rosa ayuda a distinguir claramente los elementos
    • Permite ver los nombres de línea
    • La forma de mostrar los nombres de línea todavía podría mejorar, por ejemplo apilándolos mejor
  • Firefox
    • Los nombres de área se ven más claros que en Chrome y Safari
    • Ofrece una lista de autocompletado al escribir nombres personalizados como *-start y *-end
    • Al editar grid-area de un elemento hijo, muestra la lista completa de nombres de línea disponibles

Material de referencia

1 comentarios

 
GN⁺ 2024-08-17
Opiniones en Hacker News
  • La demo animada me pareció bastante interesante, pero fue una lástima enterarme de que esa animación no estaba hecha con CSS.
    Después de aprender Flexbox pensé “con esto es suficiente” y no profundicé en Grid. Parece haber razones para preferir Grid [0], pero en general nunca necesité hacer algo que solo se pudiera hacer con Grid, y para tablas de datos uso un <table> real.
    [0] https://css-tricks.com/css-grid-replace-flexbox/

    • Es bueno haber aprendido una herramienta que cubre todo lo que necesitas.
      Solo he usado Grid para cosas como galerías de imágenes responsivas como https://labs.jensimmons.com/2016/examples/image-gallery-grid... o tarjetas responsivas como https://every-layout.dev/demos/grid-cards/. grid-template-columns vale la pena aprenderlo y grid-gap es práctico. Fuera de eso, siento que Flexbox se encarga de casi todo.
      Dicho eso, grid-template-areas todavía me resulta ambiguo. El artículo argumenta que facilita ajustar layouts por breakpoint o cuando “un compañero del equipo necesita cambiar el layout”, pero quizá simplemente no soy el público objetivo.
    • Una herramienta divertida para aprender Grid: https://cssgridgarden.com/
    • Flex es suficiente en la mayoría de los casos, pero Grid también tiene su lugar. Por ejemplo, un layout de tarjetas de 3 columnas que en pantallas pequeñas se reduce a una tarjeta por fila, una estructura de página con sidebar dedicado, o elementos que deben mantener cierta disposición incluso mientras se redimensionan.
      Puedes usar ambos según lo necesites y, combinados, se vuelven una herramienta de layout muy potente.
    • “No, Flexbox no es ‘lo suficientemente bueno’”.
      https://www.youtube.com/watch?v=MWWcZzossc8
  • Espera, ¿1/3 no es una fracción sino un rango de 1 a 3? No entiendo por qué eligieron esa sintaxis. En programación hay muchas sintaxis razonables y conocidas para representar rangos, como 1..3.

    • Lo primero que hay que saber sobre CSS es que CSS no usa la expresión de un lenguaje de programación, sino el lenguaje del layout de impresión.
      Creo que muchos de los problemas que los programadores tienen con CSS vienen de ese malentendido.
    • Me gustan las funciones de Grid, pero la sintaxis es bastante distinta del resto de CSS, así que confunde. Parece como si hubieran aislado ese rincón y lo hubieran diseñado aparte, o como si hubieran abordado el tema con un “esta vez hagámoslo bien”.
    • A ambos lados de la barra no solo pueden ir números; también pueden ir varias palabras: https://developer.mozilla.org/en-US/docs/Web/CSS/grid-column...
    • Es como imaginar que le dices a un programador que en CSS !important no significa “no importante”, sino “¡importante!”.
  • Nunca llegué a dominar bien ni Grid ni Flexbox. La última estrategia de layout que más o menos manejé bien fue float. Este artículo me dio confianza para probar CSS Grid la próxima vez que diseñe un layout, y además está muy bien hecho.

    • Si ya manejaste float, Grid y Flex te van a resultar mucho más fáciles. Reserva uno o dos días y construye algunos layouts. A diferencia de pelearse con navegadores antiguos, estos dos simplemente funcionan bien; de hecho, hasta resultan un poco aburridos.
      Hay muchos buenos artículos, pero con leer estos dos de CSS-Tricks me alcanzó:
      https://css-tricks.com/snippets/css/a-guide-to-flexbox/
      https://css-tricks.com/snippets/css/complete-guide-grid/
    • Puedes arreglártelas hasta cierto punto sin aprender Grid, pero Flexbox es casi indispensable. Es mucho más cómodo que los antiguos hacks con float y está presente en todo el CSS moderno.
      Además de los artículos de CSS-Tricks ya mencionados, recomiendo la guía de Flexbox de MDN[1] y la referencia “CSS flexible box layout”[2]. Me ayudaron a entender mejor los conceptos detrás de Flexbox, sus propiedades y cómo funcionan realmente las propiedades abreviadas.
      [1]: https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layou...
      [2]: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_flexibl...
    • Flexbox se siente como una versión bien hecha de los sistemas de grilla basados en float. Permite colocar elementos hijos tanto en vertical como en horizontal, mientras que float, con los hacks de clearfix, en la práctica solo servía para layouts por filas.
      Dicho eso, Flexbox sigue siendo más bien un layout unidimensional con posibilidad de salto de línea, así que el truco está en anidar y apilar. Grid tiene plantillas y sus hijos directos ocupan áreas predefinidas, por lo que es más estático que Flexbox, y tiene la limitación de no afectar a los elementos anidados internos. Aun así, parece que subgrid cambiará esa parte.
    • Si entendiste float, eso por sí solo ya es un logro poco común, así que probablemente puedas usar Flex/Grid con bastante gusto.
    • Grid tiene muchas funciones, pero Flex es lo bastante simple y aun así sigue siendo muy potente.
  • Recursos relacionados:
    Grid Garden https://cssgridgarden.com
    Flexbox Froggy https://flexboxfroggy.com

  • Me gustaría que hubiera una versión más básica, “antes de la introducción”, que este documento. Me trabé desde la parte introductoria y no pude avanzar. En especial, en la parte que dice “para ubicar elementos hijos dentro de Grid, hay que especificar el número de línea de cada elemento con grid-column”, no entiendo qué significa número de línea ahí.
    Seguí adelante pensando que lo entendería por contexto, pero enseguida volví a trabarme con expresiones como 1 / 3 y 1 / 4.

    • Los números de línea son las líneas que separan las columnas. Si hay 2 columnas, hay 3 líneas: en |a||b|, las dos líneas del medio en realidad se cuentan como una sola, así que hay 3 en total.
      Por eso 1/3 no es una fracción, sino un rango de columnas, y significa “empieza en la línea 1 y termina en la línea 3”.
    • Si haces scroll un poco más abajo, hay una demo en vivo donde puedes tocarlo directamente y ver qué ocurre.
      El nombre “número de línea” no es muy bueno, pero en la práctica son los bordes de las columnas. Así que 1/3 va desde el borde 1, es decir, el extremo izquierdo, hasta el borde 3, y ocupa las 2 columnas completas.
  • Para CSS Grid recomiendo muchísimo Jen Simmons Mondrian with auto flow. En https://labs.jensimmons.com/2017/01-011.html prueba presionar C y D y cambiar el tamaño de la ventana. También hay un video de YouTube para verlo junto con eso: https://www.youtube.com/watch?v=qNtJ5p3h2A4
    Es realmente genial.
    Lo que todavía quiero entender de auto flow es cómo detectar y rellenar huecos. Cuando hay objetos de tamaños variados al azar, ¿cómo se hace para que auto flow no deje espacios vacíos? ¿O se puede detectar un hueco y agregar algo?

  • Espero que no sea una pregunta tonta, pero ¿por qué definieron la sintaxis con una barra, como 1/2, 3/4? ¿No sería más natural algo como 1-2, de la columna 1 a la 2, o 1->2?

    • Los números de columna pueden ser negativos. Entonces, ¿qué sería mejor: 1--1, 1->-1 o 1/-1?
    • La flecha quizá podría funcionar, pero hay una razón para que haya espacios a ambos lados. No solo pueden ir números: https://developer.mozilla.org/en-US/docs/Web/CSS/grid-column...
      En CSS los valores ya se separan con espacios y, considerando además la intuición que solemos tener cuando aparece un guion, lo siguiente es mucho mejor:
      grid-column: 4 somegridarea / 6;
      grid-column: span 3 / 6;
      grid-column: span somegridarea / span someothergridarea;
      Es mucho más claro que escribirlo así:
      grid-column: 4 somegridarea-6;
      grid-column: span 3-6;
      grid-column: span 3->6;
      grid-column: span somegridarea-span someothergridarea;
      grid-column: span somegridarea->span someothergridarea;
  • Me encantan este tipo de artículos de blog interactivos. Para Grid, recomiendo mucho probar directamente las grid areas en herramientas como https://grid.layoutit.com/.
    Llevo años planificando layouts con Grid en ese sitio, y ajustar los espacios se vuelve mucho más fácil.

  • Quizá esta sea la primera vez que realmente entiendo CSS Grid. La visualización de números ayudó muchísimo, y es un artículo que voy a consultar seguido en adelante.

    • En las herramientas de desarrollo de Firefox también se pueden mostrar esos números de forma predeterminada. No estoy seguro de Chrome.
  • Me gustan CSS Grid y el concepto de áreas, pero sigo pensando que la parte más difícil es la gestión responsive, especialmente entre tamaños móviles y de escritorio. Según qué elemento de la UI deba estar abierto o deba ocupar toda la pantalla, muchas veces hay que actualizar grid-template-area y los tamaños de filas/columnas con JavaScript.
    Todavía no encontré un mundo donde minmax o calc lo resuelvan, y ojalá alguien sepa la respuesta.

    • https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_contain...
    • Para estos casos conviene seguir usando Grid, pero definir los valores de filas/columnas como variables CSS tipo var(--foo), en lugar de valores fijos.
      Así, desde JavaScript solo actualizas el valor de esa variable, y Grid refleja ese valor.
    • Me sorprendió que el artículo no enfatizara lo buenas que son las áreas de plantilla para lo responsive. Con media queries puedes definir distintas áreas de Grid para cada pantalla y mover cada elemento a la posición que quieras según ese tamaño. Si necesitas ocultar un elemento en cierto tamaño, le pones display: none en ese tamaño.
      Un ejemplo muy simple: https://codepen.io/trescenzi/pen/vYqpjvL
    • Creo que muchos de esos casos se podrían resolver con :has() o subgrid, aunque no tengo mucha experiencia directa.
    • ¿Has probado usar media queries?