#1 - CSS Grid Item Placement: Meu primeiro desafio frontend
Recentemente, terminei meu primeiro desafio do Frontend Mentor. Como estou começando, escolhi aquele que me pareceu o mais fácil. Ainda assim, aprendi bastante com ele e estou aqui para compartilhar um pouco do que aprendi. Se você quiser entender um pouco melhor como funciona o algoritmo de posicionamento em grids, espero que esse conteúdo lhe seja útil.
O desafio
O desafio escolhido foi o Stats preview card component[1]. Utilizei HTML e CSS básicos, mobile-first e o layout foi criado com CSS Grid.
Como ambiente de desenvolvimento, utilizei o CodeSandbox [2]. É uma boa alternativa se você não quer configurar um novo ambiente. Além disso, você pode conectar um repositório GitHub e realizar commits diretamente da sua sandbox.
Você pode acessar meu repositório e o resultado final.
O layout
O grid criado para o layout foi bastante simples: 1x2 (1 coluna x 2 linhas) para o layout mobile e 2x1 (2 colunas x 1 linha) para o layout desktop. No layout mobile, o primeiro grid item (célula) é uma imagem e o segundo é um conteúdo de texto. No layout desktop é o inverso: o primeiro grid item é o conteúdo de texto e o segundo é a imagem. A imagem abaixo ilustra os layouts.

O desafio
O problema a ser resolvido então era simples: trocar as posições dos itens do grid de acordo com layout a ser apresentado. Ou, em outras palavras, especificar, de forma explícita, a posição, de cada célula. Dá pra fazer isso em CSS? Claro que sim!
Buscando uma solução, me deparei com uma que resolveu o meu problema de forma bem direta. Bastou adicionar a seguinte declaração ao item de conteúdo de texto: grid-row: 1
.
Aqui é a hora em que podemos ficar tentados a continuar em frente sem entender muito bem o que está acontecendo. Mas acho que o melhor a se fazer nesses casos é focar nos fundamentos e entender, mesmo que superficialmente, o que acontece atrás das cortinas.
Começando a entender
A propriedade grid-row
é na verdade um atalho para as propriedades grid-row-start
e grid-row-end
, que definem, respectivamente, a linha de início e de fim de um item do grid. Também existem as propriedades grid-column-start
e grid-column-end
que fazem o mesmo para as colunas de início e fim. Essas propriedades são bem explicadas em um artigo do CSS Tricks [3].

Assim, grid-row: 1
é o mesmo que:
{
grid-row-start: 1;
grid-row-end: auto;
}
Mas, um momento... No layout de desktop, o item de texto já começava na primeira linha, bem como o item de imagem; a única coisa que mudou foi que eu defini a linha de início de forma explícita (mantendo o mesmo valor). Isso me deixou com duas dúvidas:
- Porque a ordem dos itens mudou se eu especifiquei a mesma linha que o item já ocupava?
- Se eu estou querendo trocar a ordem de duas colunas, porque estou usando uma regra que define a linha e não a coluna do item?
O algoritmo de posicionamento
Quando você cria um grid, pode especificar, usando as regras acima, a posição de cada item do grid. Mas, comumente, não fazemos isso e especificamos a posição de apenas alguns itens (ou de nenhum). Nesse caso, deixamos que um algoritmo [5] determine automaticamente a posição de cada item que não teve uma posição explicitamente especificada (chamados de itens auto placed)[6].
Explicando bem por alto, o algoritmo reserva os espaços especificados dos itens que definiram suas posições e organiza os demais itens nos espaços que sobraram. Para isso, ele mantém um cursor da sua posição atual (linha e coluna) e leva em consideração propriedades como grid-auto-flow
[7] que podem alterar a ordem dos items.
Vale notar que o algoritmo pode criar colunas e linhas adicionais se achar necessário. Assim, existe o explicit grid - o grid que você cria explicitamente com, por exemplo, grid-template-columns
e grid-template-rows
- e o implicit grid - que o algoritmo cria quando houver necessidade.
Ao especificar explicitamente a linha do item de texto com a declaração grid-row: 1
, temos a certeza de que ele necessariamente estará na primeira linha. O mesmo também é verdade quando eu especifico uma coluna. Entretanto, nesse caso, eu não especifiquei a coluna e ainda assim a ordem das colunas foi alterada. A primeira dúvida persiste.
E quanto à segunda dúvida? Por que não usar uma propridade que atue sobre a coluna do item se quero trocar a ordem das colunas? Faria mais sentido, não? Resolvi então substituir grid-row: 1
por grid-column-start: 1
, mas o resultado não foi o que eu esperava.

Eu esperava que o resultado fosse o mesmo ao usar grid-row-start: 1
já que eu estou, de igual forma, definindo explicitamente a posição do item de texto. Ele até foi para a primeira coluna, como deveria, mas agora ocupando a segunda linha; o algoritmo criou um implicit grid.
Continuando a experimentar, resolvi definir explicitamente também a coluna que o item de imagem deveria ocupar. Agora, um item está na coluna 1 e outro na coluna 2.
#text {
grid-column-start: 1;
}
#image {
grid-column-start: 2;
}
E o resultado, novamente, não foi o que eu esperava. O item de texto continuou ocupando a segunda linha.

E se eu definir explicitamente que o item de texto deve estar na primeira linha? Posso fazer isso usando a declaração grid-row-start
:
#text {
grid-column-start: 1;
grid-row-start: 1;
}
#image {
grid-column-start: 2;
}

Agora sim, funcionou! Mas tem um detalhe que talvez você tenha notado: para funcionar, eu tive que voltar a usar uma regra para definir a posição da linha.
Na verdade, se eu remover, do CSS acima, as declarações grid-column-start
, eu obtenho o mesmo resultado e, de fato, voltei ao início dessa aventura quando comecei com o grid-row: 1
apenas.
O detalhe
Ainda sem entender o que se passava, cheguei a postar minha dúvida no StackOverflow [8]. E foi aí que me mostraram o detalhe que havia passado despercebido em minha primeira leitura do algoritmo de posicionamento.
O segundo e quarto passo do algoritmo são, conforme documentação [5]:
-
- Process the items locked to a given row.
-
- Position the remaining grid items.
Agora, o mistério foi solucionado. ✔ Quando eu usei grid-row: 1
para o item de texto, ele foi processado primeiro e foi alocado para a primeira área disponível do grid (linha 1, coluna 1); ou seja, o item de texto foi processado no passo 2 e o item de imagem foi processado no passo 4.
Já quando eu usei grid-column-start: 1
para o item de texto, ambos os itens foram processados no passo 4 e, pela ordem DOM, o item de imagem foi processado primeiro e foi alocado para a primeira posição (linha 1, coluna 1). Como agora o item de texto tinha necessariamente que iniciar na coluna 1, o algoritmo criou uma linha (implicit grid) abaixo para que ele pudesse estar na coluna correta.
Quando eu adicionei grid-column-start: 2
para o item de imagem, o item de texto continuou na linha 2 por conta do cursor que mencionei mais acima; ele continua a posicionar após o último item posicionado. Esse comportamento pode ser alterado se o grid for definido como dense (ele é sparse por padrão) [7].
Conclusão
Mesmo um exercício simples como o que escolhi pode nos ensinar detalhes fundamentais se cavarmos fundo o bastante. E, depois de experimentar tanto e quebrar a cabeça tentando entender a razão das coisas, dificilmente vou esquecer essa lição. Na hora é um pouco cansativo, mas vale a pena.
Por fim, um outro método para se alterar a ordem dos itens é com a propriedade order
[9]. Mas perceba essa mudança é apenas visual e pode não ser suficiente para sua necessidade:
Since order is only meant to affect the visual order of elements and not their logical or tab order. order must not be used on non-visual media such as speech.
Referências
[1] - [https://www.frontendmentor.io/challenges/stats-preview-card-component-8JqbgoU62]
[2] - [https://codesandbox.io]
[3] - [https://css-tricks.com/snippets/css/complete-guide-grid/]
[4] - [https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/Basic_Concepts_of_Grid_Layout]
[5] - [https://drafts.csswg.org/css-grid/#auto-placement-algo]
[6] - [https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/Auto-placement_in_CSS_Grid_Layout]
[7] - [https://developer.mozilla.org/en-US/docs/Web/CSS/grid-auto-flow]
[8] - [https://stackoverflow.com/questions/68595914/css-grid-item-placement]
[9] - [https://developer.mozilla.org/en-US/docs/Web/CSS/order]