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

Grid

docs.scrimba.com

Você tem uma página com um cabeçalho no topo, uma barra lateral à esquerda, uma área de conteúdo principal e um rodapé. Você poderia aninhar uma pilha de containers e ajustar cada um em seu lugar, e funcionaria na maioria das vezes até o dia em que você precisar mudar a disposição. CSS grid foi construído exatamente para esse tipo de problema: distribuir uma página em linhas e colunas ao mesmo tempo. Uma vez que você consegue descrever um layout como um conjunto de tracks, a maior parte da bagunça com wrappers e floats desaparece.

O container grid

Você transforma qualquer elemento em um grid dando a ele display: grid. Esse elemento se torna o grid container, e seus filhos diretos se tornam itens que se encaixam em um grid que você define. Por si só, display: grid não faz muito, então você também precisa dizer quantas colunas e linhas deseja e qual o tamanho de cada uma.

Você descreve as colunas com grid-template-columns e as linhas com grid-template-rows. Cada valor na lista é um track, e um track é uma única coluna ou linha:

css
.layout {
  display: grid;
  grid-template-columns: 200px 1fr;   /* duas colunas: uma fixa, depois o resto */
  grid-template-rows: 80px 400px;     /* duas linhas: uma curta, depois uma alta */
}

Configurar display: grid em um elemento o torna um grid container, e seus filhos diretos se tornam grid items dispostos em um grid que você define. Esse é o equivalente bidimensional do flexbox, que distribui itens ao longo de um único eixo de cada vez. Flexbox pergunta "como essa linha (ou coluna) de itens deve compartilhar espaço?"; grid pergunta "onde esses itens se sentam em um conjunto de linhas e colunas?".

Você define os tracks com grid-template-columns e grid-template-rows. Cada valor é um track, uma coluna ou uma linha, e os valores podem misturar unidades: comprimentos fixos, percentuais ou a unidade flexível fr que você encontrará na próxima seção.

css
.layout {
  display: grid;
  grid-template-columns: 200px 1fr;   /* barra lateral fixa, coluna principal flexível */
  grid-template-rows: auto 1fr auto;  /* cabeçalho se ajusta ao conteúdo, principal preenche, rodapé se ajusta */
}

display: grid estabelece um grid formatting context no elemento: ele se torna um grid container, seus filhos diretos se tornam grid items, e as regras de normal flow que governavam esses filhos não se aplicam mais. Text nodes são envolvidos em items anônimos, e propriedades como float e vertical-align deixam de ter qualquer efeito nos items, porque seu posicionamento agora é responsabilidade do grid.

A diferença do flexbox é a dimensionalidade, e é a primeira decisão a acertar. Flexbox é unidimensional: distribui itens ao longo de um eixo principal e envolve como efeito colateral, mas não alinha conteúdo em um grid correspondente no eixo transversal. Grid é bidimensional: define linhas e colunas juntas, então a posição de linha e a posição de coluna de um item são definidas independentemente e os itens se alinham em ambos os eixos de uma vez. Você define os tracks explícitos com grid-template-columns e grid-template-rows, cada valor produzindo um track:

css
.layout {
  display: grid;
  grid-template-columns: 200px 1fr;   /* dois tracks de coluna explícitos */
  grid-template-rows: auto 1fr auto;  /* conteúdo, preenche, conteúdo */
}

A palavra-chave auto dimensiona um track ao seu conteúdo; 1fr absorve o espaço restante, que é o mecanismo que a próxima seção se baseia.

JunoO grid container Adicione display: grid a um elemento e ele se torna um grid container, com seus filhos diretos sentando dentro como items. Depois você diz quantas colunas e linhas deseja com grid-template-columns e grid-template-rows, um valor por track. Nada se alinha até que você defina esses tracks, então essa é sempre seu primeiro passo.
JunoO grid container Flexbox funciona ao longo de um eixo de cada vez; grid funciona em linhas e colunas juntas, o que é por isso que layouts de página parecem mais naturais em grid. Configure display: grid, depois liste seus tracks em grid-template-columns e grid-template-rows. Recorra ao grid quando estiver posicionando coisas em um arranjo bidimensional, e ao flexbox quando estiver alinhando uma linha ou coluna.
JunoO grid containerdisplay: grid cria um grid formatting context, então os filhos deixam de obedecer ao normal flow e float e vertical-align silenciosamente deixam de importar neles. A verdadeira separação do flexbox é a dimensionalidade: flex distribui ao longo de um eixo, grid posiciona em ambos ao mesmo tempo. Escolha grid quando a posição de linha e coluna são ambas significativas, flex quando apenas um eixo é.

Tracks flexíveis

Colunas de pixels fixos são boas, mas a maioria dos layouts quer colunas que compartilhem o espaço uniformemente e cresçam com a tela. Isso é para o que a unidade fr serve. Um fr significa uma parte do espaço restante, então três colunas de 1fr cada levam um terço do container:

css
.gallery {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;   /* três colunas iguais */
}

Digitar 1fr três vezes fica cansativo, então repeat() escreve por você. E gap define o espaço entre os tracks, então você não precisa recorrer a margins em cada item:

css
.gallery {
  display: grid;
  grid-template-columns: repeat(3, 1fr);   /* as mesmas três colunas iguais */
  gap: 16px;                               /* espaço entre linhas e colunas */
}

A unidade fr mede uma parte do espaço livre no container depois que tamanhos fixos e gaps são subtraídos. Três colunas em 1fr cada recebem um terço igual; um par 2fr 1fr divide o espaço na proporção de dois para um. Porque fr divide o que sobra, as colunas permanecem proporcionais conforme o container cresce ou encolhe, coisa que comprimentos fixos não conseguem fazer.

Dois auxiliares tornam as listas de tracks legíveis. repeat(3, 1fr) se expande para 1fr 1fr 1fr, e gap define os gutters entre tracks em uma propriedade (com row-gap e column-gap quando você quer que sejam diferentes):

css
.gallery {
  display: grid;
  grid-template-columns: repeat(3, 1fr);   /* três colunas iguais */
  gap: 16px;                               /* gutters de 16px, linhas e colunas */
}

Gutters são definidos com gap, não com margins nos items. Porque gap só se aplica entre tracks e nunca nas bordas externas, o grid fica alinhado ao seu container enquanto os items permanecem uniformemente espaçados.

A unidade fr é um flexible length: ela representa uma fração do espaço livre do container, o espaço que permanece depois que tamanhos de track fixos, tracks dimensionados pelo conteúdo e gaps são resolvidos. Uma lista de tracks 2fr 1fr 1fr entrega metade do espaço livre para a primeira coluna e um quarto para cada uma das outras duas. A sutileza é que fr distribui espaço livre, não largura total, então um track contendo conteúdo largo pode ultrapassar sua parte fr a menos que você o limite, que é onde minmax() na última seção entra.

repeat() é uma forma compacta de escrever uma sequência de tracks: repeat(3, 1fr) é 1fr 1fr 1fr, e ele compõe, então repeat(2, 200px 1fr) produz quatro tracks. gap (o nome moderno para grid-gap) define gutters apenas entre tracks, nunca ao redor do exterior do grid, então não compete com o próprio padding do container.

css
.gallery {
  display: grid;
  grid-template-columns: repeat(3, 1fr);   /* três colunas iguais */
  gap: 16px 24px;                          /* gap de 16px em linhas, 24px em colunas */
}

Note o gap de dois valores: gap de linha primeiro, depois gap de coluna. Um valor único se aplica a ambos.

JunoTracks flexíveis Um fr é uma parte do espaço restante, então 1fr 1fr 1fr te dá três colunas iguais. Use repeat(3, 1fr) para que você não esteja digitando o mesmo valor repetidamente, e gap para o espaço entre tracks. Uma vez que fr clicou para mim, parei de recorrer a percentuais que nunca somavam corretamente.
JunoTracks flexíveisfr divide o espaço livre no container, então colunas proporcionais permancem proporcionais conforme a página é redimensionada. Confie em repeat() para manter listas de tracks curtas e gap para gutters em vez de margins por item. Lembre-se que gap só fica entre tracks, nunca na borda externa, que é geralmente exatamente o que você quer.
JunoTracks flexíveisfr divide espaço livre, não largura total, então um track com conteúdo largo pode ultrapassar sua parte até que você o limite com minmax(). repeat() compõe, então repeat(2, 200px 1fr) é quatro tracks. E gap de dois valores lê gap de linha primeiro, depois gap de coluna, que confunde pessoas que assumem que combina com o atalho no sentido horário.

Posicionando items

Por padrão, cada item cai na próxima célula livre, um por célula, em ordem. Quando você quer que um item ocupe mais de uma célula, você diz assim com grid-column e grid-row. As linhas entre tracks são numeradas começando em 1, então grid-column: 1 / 3 significa "comece na linha 1, termine na linha 3", cobrindo duas colunas:

css
.featured {
  grid-column: 1 / 3;   /* estenda da linha de coluna 1 para a linha 3, duas colunas de largura */
}

Se você não quer contar linhas, span diz quantas células cobrir a partir de onde o item cai:

css
.featured {
  grid-column: span 2;   /* cubra duas colunas, começando de onde este item se senta */
}

O posicionamento em grid é descrito com grid lines, as linhas numeradas que ficam entre e ao redor dos tracks. Um grid de três colunas tem quatro linhas de coluna, 1 até 4. grid-column: 1 / 3 posiciona um item da linha 1 para a linha 3, então ele abrange as duas primeiras colunas; grid-row faz o mesmo verticalmente. A palavra-chave span evita contar: grid-column: span 2 cobre duas colunas a partir de onde o item é posicionado.

Para um layout de página inteira, nomear as regiões lê melhor do que contar linhas. grid-template-areas permite que você desenhe o layout como um conjunto de células nomeadas, depois atribua cada item a um nome:

css
.page {
  display: grid;
  grid-template-columns: 200px 1fr;
  grid-template-areas:
    "sidebar header"
    "sidebar main";     /* sidebar abrange ambas as linhas repetindo seu nome */
}

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

O posicionamento funciona em grid lines, os limites numerados ao redor de cada track (um eixo com n tracks tem n + 1 linhas). grid-column: 1 / 3 define as linhas de coluna inicial e final, abrangendo os tracks entre elas; grid-column: span 2 define um span sem fixar um início, deixando o algoritmo de auto-placement escolher onde ele cai. Números de linha negativos contam do fim, então grid-column: 1 / -1 sempre abrange a largura total independentemente da contagem de colunas, que é a forma durável de escrever uma linha full-bleed.

grid-template-areas nomeia células para que você posicione items por nome em vez de por número de linha. Cada string é uma linha, cada token uma célula, e repetir um token entre células faz um item abranger elas. O bloco formatado com espaço em branco funciona também como um diagrama legível do layout:

css
.page {
  display: grid;
  grid-template-columns: 200px 1fr;
  grid-template-rows: auto 1fr;
  grid-template-areas:
    "sidebar header"
    "sidebar main";     /* sidebar ocupa ambas as linhas da coluna um */
}

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

Duas regras mantêm a honestidade: cada string de linha deve ter o mesmo número de células, e as células para um nome devem formar um retângulo sólido, ou a declaração é inválida e ignorada. Um token . marca uma célula vazia que você quer deixar em branco.

JunoPosicionando items Items preenchem uma célula cada por padrão, e você faz um estender entre células com grid-column ou grid-row. Números de linha começam em 1, então grid-column: 1 / 3 cobre duas colunas, ou use span 2 se você preferir não contar. Isso é o suficiente para construir a maioria dos layouts antes de você nomear uma única área.
JunoPosicionando items Posicione items com grid lines: grid-column: 1 / 3 abrange duas colunas, e span 2 faz isso sem contar a partir de um início fixo. Para uma página inteira, grid-template-areas permite nomear as regiões e ler o layout de uma vez, que bate rastrear números de linha manualmente. Repita um nome entre células e essa região as abrange.
JunoPosicionando items Linhas podem ser negativas, então grid-column: 1 / -1 abrange a largura total não importa quantas colunas existem, que é o truque full-bleed confiável. Com grid-template-areas, toda string de linha precisa de células iguais e cada região nomeada deve ser um retângulo sólido, ou a declaração inteira é descartada. Use um token . para deixar uma célula deliberadamente vazia.

Grids responsivos sem media queries

Uma linha de cards deve mostrar três na largura, dois em um tablet, um em um telefone. Você pode fazer isso apenas com grid, sem breakpoints para escrever. O truque é uma linha:

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

Leia de dentro para fora. minmax(200px, 1fr) significa que cada coluna é no mínimo 200px e no máximo uma parte do espaço. auto-fit então encaixa quantas dessas colunas o container tem espaço. Tela larga, mais colunas encaixam; tela estreita, menos encaixam, e os cards refluem por conta própria.

O padrão que reflu cards sem uma única media query é repeat(auto-fit, minmax(200px, 1fr)). Cada parte faz um trabalho. minmax(200px, 1fr) define um track que nunca é menor que 200px e nunca maior que uma parte fr. auto-fit repete esse track quantas vezes couber na largura atual, então a contagem de colunas responde ao container em vez de responder a breakpoints fixos.

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

O piso 200px é seu controle real: é a mais estreita que um card é permitido ficar antes do grid cair para menos colunas. Isso se emparelha naturalmente com as técnicas fluidas em responsive design, e geralmente substitui as media queries que você teria que escrever para um grid de cards.

repeat(auto-fit, minmax(200px, 1fr)) é o idioma canonical de grid responsivo, e cada parte merece seu lugar. minmax(min, max) define um track com um limite inferior e superior: minmax(200px, 1fr) nunca encolhe abaixo de 200px e nunca cresce acima de uma parte de espaço livre. O piso 200px define o limiar de refluxo, a largura em que o grid ganha ou perde uma coluna.

A escolha entre auto-fit e auto-fill é a parte que vale a pena saber. Ambos computam quantos tracks minmax() cabem no container. auto-fill mantém os tracks vazios restantes no grid, então uma linha meia vazia de cards fica em sua largura de coluna. auto-fit colapsa esses tracks vazios para largura zero, então os items presentes se expandem para preencher a linha:

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

Observe uma borda: minmax(200px, 1fr) pode extravasar um container mais estreito que 200px mais gaps, porque o piso é um mínimo rígido. minmax(min(200px, 100%), 1fr) protege contra isso deixando o piso cair para a largura do container em telas muito pequenas. Para dimensionar o piso confiável entre dispositivos, sizing units cobre como as unidades de comprimento resolvem.

JunoGrids responsivos sem media queriesrepeat(auto-fit, minmax(200px, 1fr)) faz cards refluxarem por conta própria, sem breakpoints necessários. Cada coluna é no mínimo 200px e no máximo uma parte do espaço, e auto-fit encaixa quantas couberem. Mude o 200px e você muda quantos cards ficam lado a lado.
JunoGrids responsivos sem media queries Uma linha, repeat(auto-fit, minmax(200px, 1fr)), substitui uma pilha de media queries de grid de cards. O piso 200px é a alavanca: ele decide como um card fica estreito antes do grid cair uma coluna. Recorra a isso antes de escrever breakpoints para qualquer coisa que seja realmente um grid refluente de cards.
JunoGrids responsivos sem media queriesauto-fit colapsa tracks vazios então items presentes se expandem para preencher; auto-fill mantém os tracks vazios e deixa gaps, que é a diferença inteira entre eles. Observe o caso de overflow: um piso rígido 200px pode extravasar em containers muito estreitos, então minmax(min(200px, 100%), 1fr) é o piso mais seguro. O piso é o que define seus pontos de refluxo, então escolha com o card mais sensatamente pequeno em mente.

Grids explícitos e implícitos

Tudo até agora define o explicit grid: os tracks que você nomeia em grid-template-columns e grid-template-rows. Quando items caem fora desse grid definido, o navegador cria tracks para mantê-los, e esses formam o implicit grid. Adicione um quarto item a um grid explícito de três colunas, uma linha e ele começa uma nova segunda linha criada implicitamente. Tracks implícitos se dimensionam auto por padrão, que é por isso que uma linha implícita é apenas tão alta quanto seu conteúdo a menos que você diga o contrário.

grid-auto-rows define o tamanho dessas linhas implícitas (e grid-auto-columns as colunas implícitas), então um grid de cards cuja contagem de linhas você não consegue prever ainda recebe linhas uniformes:

css
.gallery {
  display: grid;
  grid-template-columns: repeat(3, 1fr);   /* explícito: três colunas */
  grid-auto-rows: 240px;                   /* linhas implícitas têm 240px cada */
  gap: 16px;
}

O alinhamento então decide onde items e tracks se sentam dentro de suas células. justify-items alinha items ao longo do eixo de linha (inline) e align-items ao longo do eixo de coluna (block), cada um aceitando start, end, center, ou stretch (o padrão, que preenche a célula). place-items é o atalho para ambos, eixo block primeiro:

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

minmax() também toma as palavras-chave de conteúdo min-content e max-content: min-content é o menor que um track pode ser sem overflowrar (aproximadamente a palavra mais longa ininterrupta), e max-content é o tamanho que o conteúdo quer quando nada o força a quebrar. Um track como minmax(min-content, max-content) se dimensiona ao conteúdo dentro desses limites. E subgrid deixa um grid aninhado herdar as linhas de track de seu pai, então as colunas de um grid filha se alinham com o grid externo em vez de definirem seu próprio.

Na decisão de grid-versus-flex, a regra clara é essa. Se você está arranjando conteúdo em um eixo e deixando que ele envolva como consequência, use flexbox: uma barra de navegação, uma linha de tags, uma barra de ferramentas. Se você está posicionando conteúdo em linhas e colunas que devem se alinhar em ambos os eixos, use grid: um shell de página, uma galeria de cards, um formulário com rótulos alinhados e campos. Eles se combinam bem, então uma célula grid frequentemente contém um flex container, e essa combinação cobre a maioria dos layouts que você construirá.

JunoGrids explícitos e implícitos Os tracks que você declara são o grid explícito; qualquer coisa que o navegador adiciona para manter items que extravasam é o grid implícito, e esses tracks extras são auto-dimensionados até que grid-auto-rows ou grid-auto-columns diga o contrário. O alinhamento vive em justify-items e align-items, com place-items como o atalho e stretch como o padrão. A decisão é um eixo com envolvimento significa flexbox, dois eixos que devem se alinhar significa grid, e eles se aninham felizmente.