2 pontos por GN⁺ 2024-08-17 | 1 comentários | Compartilhar no WhatsApp
  • O CSS Grid passou a ser amplamente suportado pelos principais navegadores desde março de 2017, mas grid-template-areas ainda é menos usado e permite expressar visualmente o layout dentro do CSS sem calcular números de linhas
  • grid-template-areas funciona posicionando nomes de áreas em strings e vinculando elementos filhos com grid-area; o mesmo nome deve obrigatoriamente formar uma área retangular
  • Linhas de grade nomeadas são uma forma de atribuir nomes às linhas, como content-start / content-end, e os padrões *-start e *-end podem ser usados pelo navegador como áreas implícitas
  • Em cards invertidos, headers responsivos, layouts editoriais, posts no estilo Threads, cards sobrepostos e layouts condicionais com :has(), é possível gerenciar variações de posicionamento alterando apenas a string de áreas no elemento pai
  • Chrome, Safari e Firefox oferecem DevTools para áreas de Grid; no Firefox, a exibição dos nomes das áreas e o autocompletar de nomes de linhas possíveis ao editar grid-area são especialmente úteis

Tornando layouts mais legíveis com grid-template-areas

  • Em posicionamentos tradicionais com CSS Grid, é comum especificar diretamente números de linhas, como em grid-column: 1 / 3
  • Números de linhas não ficam visíveis até serem conferidos no DevTools e, em layouts com colunas e linhas, é difícil calcular mentalmente os números corretos
  • grid-template-areas dá nomes a cada célula para posicionamento, fazendo com que o próprio código CSS pareça um mapa do 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;
}
  • Elementos filhos são mapeados para áreas nomeadas com grid-area
  • Em um exemplo de card, é possível definir algo como "featured featured article" para fazer a área featured ocupar 2 colunas e a área article ocupar 1 coluna

Sintaxe e regras obrigatórias

  • grid-template-areas recebe uma ou mais strings de áreas
    • Uma única string cria um layout unidimensional apenas com colunas
    • Várias strings compõem um layout multidimensional com linhas e colunas
  • Ao usar várias strings, quebrar as linhas torna o layout mais fácil de ler
.element {
  display: grid;
  grid-template-columns: 200px 1fr;
  grid-template-areas:
    "aside main"
    "footer footer";
}
  • Cada string representa uma linha da grade e pode ser pensada como uma tabela
  • Áreas definidas com o mesmo nome devem formar um retângulo no 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 as linhas devem ter o mesmo número de tokens de área e, mesmo que uma área necessária não seja usada, a célula em si deve ser definida
  • Células vazias podem ser representadas por um ou mais pontos
.element {
  grid-template-areas:
    "aside main"
    "... footer";
}
  • O ponto é o token de célula nula da especificação do CSS Grid e representa uma célula vazia da grade

Relação entre linhas de grade nomeadas e áreas

  • No CSS Grid, há uma linha a mais do que o número de colunas
    • Com 3 colunas, são criadas 4 linhas de grade
  • Linhas de grade nomeadas são uma forma de dar nomes exclusivos às linhas em vez de usar os números padrão
.layout {
  grid-template-columns:
    [full-start] 1fr
    [content-start] 2fr
    [content-end] 1fr [full-end];
}

.item {
  grid-column: content-start / content-end;
}
  • Mesmo dando nomes às linhas, as linhas numéricas continuam disponíveis
  • Tamanho de trilha (track size) significa o tamanho de uma coluna ou linha, e valores como 1fr 1fr são tamanhos de trilha
  • Em linhas nomeadas, nomeiam-se as linhas ao redor das trilhas
.layout {
  display: grid;
  grid-template-columns:
    [aside-start] 200px [aside-end main-start] 1fr [main-end];
}
  • Uma linha pode compartilhar vários nomes; no exemplo acima, aside-end e main-start são a mesma linha
  • Ao definir nomes *-start / *-end, como aside-start e aside-end, o navegador permite usos como grid-column: aside por meio de nomes de linha implícitos
  • Não é necessário nomear todas as linhas; é possível nomear seletivamente apenas as linhas importantes
  • No posicionamento, números e nomes podem ser misturados, como em grid-column: 1 / content-end

Gerenciando variações de posicionamento pela string de áreas do pai

  • Com grid-template-areas, é possível manter os nomes grid-area dos filhos e alterar apenas a string de áreas do elemento pai para mudar o layout inteiro
.aside {
  grid-area: aside;
}

.main {
  grid-area: main;
}

.footer {
  grid-area: footer;
}
  • Mantendo os mesmos nomes aside, main e footer, basta alterar a string de grid-template-areas para que todo o posicionamento seja atualizado automaticamente
  • O controle do layout fica centralizado na definição de áreas do pai, facilitando ajustes

Invertendo a direção de cards

  • No Flexbox, é fácil inverter a direção de um card com flex-direction: row-reverse
  • No CSS Grid, ao usar números de linhas, mudar a direção exige alterar a definição das colunas e também o valor de grid-column de cada filho
  • Com áreas nomeadas, basta atribuir a imagem e o conteúdo do card a áreas e depois mudar apenas a ordem das áreas no pai
.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";
}
  • O mesmo posicionamento também pode ser expresso com a propriedade abreviada grid-template
.card--flip {
  grid-template: "content image" / 1fr 150px;
}
  • A propriedade abreviada é opcional, e também é válido preferir a propriedade longa por considerá-la mais legível

Layout de header responsivo

  • Um header com logo, navegação e área de ações pode começar com 3 colunas do mesmo tamanho
  • Usando números de linhas, seria necessário especificar grid-column para .logo, .nav e .actions individualmente
  • Com nomes de áreas, cada filho é mapeado para logo, nav e actions, e por viewport basta mudar grid-template-areas no pai
.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;
}
  • Em tamanhos menores, é possível colocar o logo e as ações na primeira linha e a navegação em toda a largura
.header {
  grid-template-areas:
    "logo logo actions"
    "nav nav nav";
}
  • A partir de 380px, é possível deixar o logo à esquerda e posicionar a navegação e as ações à direita
@media (min-width: 380px) {
  .header {
    grid-template-areas:
      "logo nav nav"
      "logo actions actions";
  }

  .nav {
    justify-self: end;
  }
}
  • A partir de 900px, é possível voltar para o layout em uma linha
@media (min-width: 900px) {
  .header {
    grid-template-areas: "logo nav actions";
  }
}
  • A string de áreas funciona como um mapeamento que mostra diretamente o posicionamento da UI dentro do CSS

Exemplo de layout editorial

  • Uma seção com título, texto e imagem pode mudar facilmente o posicionamento por tamanho de viewport usando grid-template-areas
.section {
  display: grid;
  grid-template-areas:
    ". title title"
    "thumb content content";
  gap: 1rem;
}
  • O ponto à esquerda do título é um token de célula nula, indicando espaço vazio
  • Em um exemplo de seção no estilo time.com, são usadas as áreas feature, secondary e most-read junto com colunas vazias dos dois 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;
}
  • As colunas vazias dos dois lados servem principalmente como espaçamento lateral
  • Na versão responsiva, em telas pequenas feature, secondary e most-read são empilhados verticalmente, e a partir de 500px e 900px as definições de colunas e áreas são alteradas
  • grid-template-rows pode ser substituído pela definição de áreas, portanto não é indispensável

Componente de post no estilo Threads

  • Ao revisar o CSS do Threads app by Meta, é possível observar casos de uso de CSS Grid em componentes de post
  • O exemplo original posiciona itens com grid-template-columns, grid-template-rows e números de linhas
.postBody {
  grid-column-start: 2;
  grid-row-start: 2;
  grid-row-end: span 3;
}
  • Várias variações de posts podem ser expressas mais facilmente com 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";
}
  • É possível distinguir as variações padrão, resposta e post aninhado apenas olhando para as strings de áreas

Itens sobrepostos e nomes de áreas

  • Em grid-template-areas, o mesmo nome deve formar um retângulo; portanto, repetir o mesmo nome em uma forma não retangular é inválido
.layout {
  display: grid;
  grid-template-columns: 1fr 1fr fr;
  grid-template-areas:
    "card tag tag"
    "title title card";
}
  • O exemplo acima é invalid porque card não forma um retângulo
  • Em cards sobrepostos, é possível definir novos nomes de área, como thumb-1 e thumb-2, e usar esses nomes em grid-column e 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;
}
  • A tag e o título podem ser posicionados em seus respectivos grid-area e alinhados com align-self e justify-self
  • Se necessário, é preciso gerenciar a ordem de empilhamento dos elementos filhos, mas no exemplo a ordem do código-fonte resolve isso
  • Este exemplo de sobreposição foi inspirado na página Oddbird’s Cascading Layouts

:has() e layout condicional

  • Ao combinar o seletor CSS :has() com áreas de Grid, é possível mudar o layout conforme a presença de um elemento específico
  • É possível aplicar definições de áreas diferentes quando há ou não figcaption dentro de <figure>
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 .";
}

Suporte a direções multilíngues LTR/RTL

  • O CSS Grid ajusta o layout de acordo com a direção da página, seja LTR ou RTL
  • Áreas de grade nomeadas também seguem a direção da página, portanto o layout é invertido em uma configuração RTL
  • Como material relacionado à criação de layouts RTL, há o guia RTL Styling 101

Diferenças no suporte das DevTools

  • Chrome, Safari e Firefox oferecem DevTools para áreas de Grid
  • Chrome
    • Posiciona os nomes das áreas no canto superior esquerdo, o que pode fazer as áreas parecerem sobrepostas
    • A sobreposição de cores pode alterar a forma como o design é visto
  • Safari
    • O contorno rosa ajuda a distinguir claramente os itens
    • Permite ver os nomes das linhas
    • A forma de exibir nomes de linhas ainda pode ser melhorada, por exemplo mostrando-os empilhados
  • Firefox
    • Os nomes das áreas aparecem com mais clareza do que no Chrome e no Safari
    • Oferece uma lista de autocompletar ao inserir nomes personalizados como *-start e *-end
    • Ao editar grid-area de um item filho, oferece uma lista de todos os nomes de linhas possíveis

Referências

1 comentários

 
GN⁺ 2024-08-17
Opiniões no Hacker News
  • A demo de animação era bem interessante, mas fiquei decepcionado ao descobrir que a animação não foi feita em CSS
    Depois de aprender Flexbox, pensei “isso já é suficiente” e não me aprofundei em Grid. Parece haver motivos para preferir Grid [0], mas, no geral, nunca precisei fazer algo que só fosse possível com Grid, e para tabelas de dados uso <table> de verdade
    [0] https://css-tricks.com/css-grid-replace-flexbox/

    • É bom ter aprendido uma ferramenta que cobre tudo de que você precisa
      Só usei Grid para coisas como galerias de imagens responsivas, como https://labs.jensimmons.com/2016/examples/image-gallery-grid..., ou cartões responsivos como https://every-layout.dev/demos/grid-cards/. Vale a pena aprender grid-template-columns, e grid-gap é conveniente. Fora isso, parece que Flexbox resolve quase tudo
      Dito isso, grid-template-areas ainda me parece meio ambíguo. O texto argumenta que é fácil para ajustar layouts por breakpoint ou “quando um colega de equipe precisa mudar o layout”, mas talvez eu simplesmente não seja o público-alvo
    • Uma ferramenta divertida para aprender Grid: https://cssgridgarden.com/
    • Flex é suficiente na maioria dos casos, mas Grid também tem seu lugar. É o caso de um layout de cartões em 3 colunas que vira um cartão por linha em telas pequenas, uma estrutura de página com sidebar dedicada, ou elementos que precisam manter uma disposição específica mesmo durante redimensionamento
      Dá para usar os dois conforme a necessidade e, combinados, eles se tornam uma ferramenta de layout muito poderosa
    • “Não, Flexbox não é ‘bom o suficiente’”
      https://www.youtube.com/watch?v=MWWcZzossc8
  • Espera, 1/3 não é uma fração, mas um intervalo de 1 a 3? Não entendo por que escolheriam essa sintaxe. Em programação há muitas sintaxes razoáveis e bem conhecidas para representar intervalos, como 1..3

    • A primeira coisa que é preciso saber sobre CSS é que CSS não usa a expressão de uma linguagem de programação, e sim a linguagem de layout de impressão
      Parece que boa parte dos problemas que programadores têm com CSS vem desse mal-entendido
    • Gosto dos recursos de Grid, mas a sintaxe é bem diferente do restante do CSS, o que confunde. Parece que esse canto foi criado de forma isolada, ou como se tivessem abordado com a ideia de “desta vez vamos fazer direito”
    • Não são apenas números que podem aparecer dos dois lados da barra; várias palavras também podem: https://developer.mozilla.org/en-US/docs/Web/CSS/grid-column...
    • É como imaginar alguém dizendo a um programador que, em CSS, !important não significa “não importante”, mas sim “importante!”
  • Nunca peguei direito nem Grid nem Flexbox. A última estratégia de layout com que eu ainda me virava bem foi float. Este texto me deu confiança para tentar usar CSS Grid quando eu for projetar o próximo layout, e o artigo também é bem feito

    • Se você já lidou com float, Grid e Flex serão muito mais fáceis. Basta reservar um ou dois dias e montar alguns layouts. Diferentemente de brigar com navegadores antigos, os dois simplesmente funcionam bem e, na verdade, chegam a ser meio entediantes
      Há muitos textos bons, mas, para mim, bastou ler estes dois do CSS-Tricks
      https://css-tricks.com/snippets/css/a-guide-to-flexbox/
      https://css-tricks.com/snippets/css/complete-guide-grid/
    • Dá para se virar até certo ponto sem aprender Grid, mas Flexbox é quase obrigatório. Ele é muito mais conveniente do que os antigos hacks com float e está por trás de grande parte do CSS moderno
      Além dos artigos do CSS-Tricks já citados, recomendo o guia de Flexbox da MDN[1] e a referência “CSS flexible box layout”[2]. Eles me ajudaram a entender mais a fundo os conceitos por trás do Flexbox e como propriedades e propriedades abreviadas realmente funcionam
      [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 parece uma versão bem-feita dos sistemas de grid baseados em float. Você consegue posicionar elementos filhos tanto na vertical quanto na horizontal, enquanto float com hacks de clearfix era, na prática, apenas posicionamento por linhas
      Ainda assim, Flexbox é mais parecido com um layout unidimensional com possibilidade de quebra de linha, então o truque é aninhar e empilhar. Grid é mais estático que Flexbox: ele tem templates, e os filhos diretos ocupam áreas predefinidas; há a limitação de não afetar elementos aninhados internamente. Mesmo assim, parece que subgrid deve mudar essa parte
    • Se você entendeu float, isso por si só já é uma conquista rara, então provavelmente vai conseguir usar Flex/Grid com bastante prazer
    • Grid tem muitos recursos, mas Flex é simples o bastante e ainda assim extremamente poderoso
  • Materiais relacionados:
    Grid Garden https://cssgridgarden.com
    Flexbox Froggy https://flexboxfroggy.com

  • Seria bom existir uma versão ainda mais básica que este documento, algo “antes da introdução”. Travei já na parte introdutória e não consegui avançar. Especialmente no trecho “para posicionar itens filhos dentro de um Grid, é preciso especificar o número da linha de cada item com grid-column”: eu não sabia o que era esse número da linha aqui
    Tentei seguir em frente achando que entenderia pelo contexto, mas logo travei de novo em expressões como 1 / 3 e 1 / 4

    • Os números de linha são as linhas que separam as colunas. Se há 2 colunas, há 3 linhas: em |a||b|, as duas linhas do meio contam na prática como uma só, então são 3 no total
      Portanto 1/3 não é uma fração, mas um intervalo de colunas, e significa “começa na linha 1 e termina na linha 3”
    • Se você rolar um pouco para baixo, há uma demo ao vivo em que dá para mexer diretamente e ver o que acontece
      O nome “número da linha” não é muito bom, mas na prática são as bordas das colunas. Então 1/3 vai da borda 1, ou seja, a mais à esquerda, até a borda 3, ocupando as 2 colunas inteiras
  • Para CSS Grid, recomendo muito Jen Simmons Mondrian with auto flow. Em https://labs.jensimmons.com/2017/01-011.html, pressione C e D e redimensione a janela. Há também um vídeo no YouTube para assistir junto: https://www.youtube.com/watch?v=qNtJ5p3h2A4
    É realmente incrível
    O que eu ainda quero entender no auto flow é como detectar e preencher espaços vazios. Quando há objetos de tamanhos variados distribuídos aleatoriamente, como fazer o auto flow não deixar lacunas? Ou será que dá para detectar lacunas e adicionar algo nelas?

  • Espero que não seja uma pergunta idiota, mas por que a sintaxe foi definida com barra, como 1/2, 3/4? Algo como 1-2, da coluna 1 até a coluna 2, ou 1->2, não seria mais natural?

    • Os números das colunas podem ser negativos. Então o que seria melhor: 1--1, 1->-1 ou 1/-1?
    • Setas talvez fossem possíveis, mas há um motivo para existir espaço dos dois lados. Não é só número que pode aparecer: https://developer.mozilla.org/en-US/docs/Web/CSS/grid-column...
      Em CSS, valores já são separados por espaços, e considerando também a intuição que normalmente temos quando aparece um hífen, o abaixo é muito melhor
      grid-column: 4 somegridarea / 6;
      grid-column: span 3 / 6;
      grid-column: span somegridarea / span someothergridarea;
      Muito mais claro do que escrever assim
      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;
  • Gosto muito desse tipo de post interativo de blog. Para Grid, recomendo muito mexer diretamente em grid areas em ferramentas como https://grid.layoutit.com/
    Uso esse site há anos para planejar layouts com Grid, e ficou muito mais fácil ajustar os espaçamentos

  • Talvez esta seja a primeira vez que realmente entendi CSS Grid. A exibição da numeração ajudou muito, e é um artigo que vou consultar com frequência daqui para frente

    • No Firefox DevTools também dá para exibir esses números por padrão. No Chrome não tenho certeza
  • Gosto de CSS Grid e do conceito de áreas, mas ainda acho que a parte mais difícil é o gerenciamento responsivo, especialmente entre tamanhos mobile e desktop. Dependendo de qual elemento da UI deve estar aberto ou ocupar a tela inteira, muitas vezes é preciso atualizar grid-template-area e os tamanhos de linhas/colunas via JavaScript
    Ainda não encontrei um mundo em que minmax ou calc resolvam isso, e gostaria que alguém soubesse a resposta

    • https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_contain...
    • Nesses casos, uma boa abordagem é continuar usando Grid, mas definir os valores de linhas/colunas como variáveis CSS, como var(--foo), em vez de valores fixos
      Assim, no JavaScript você só precisa atualizar o valor dessa variável, e o Grid reflete esse valor
    • Achei curioso o texto não enfatizar o quanto áreas de template são boas para responsividade. Com media queries, dá para definir áreas de Grid diferentes para cada tela e mover cada elemento para a posição desejada naquele tamanho de tela. Se for preciso ocultar um elemento em determinado tamanho, basta aplicar display: none nesse tamanho
      Um exemplo bem simples: https://codepen.io/trescenzi/pen/vYqpjvL
    • Acho que muitos casos assim podem ser resolvidos com :has() ou subgrid, mas não tenho muita experiência prática
    • Você já tentou usar media queries?