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.