Curso de CSS / Grid: repeat(), auto-fit, auto-fill e áreas

O CSS Grid pode repetir faixas com repeat() e adaptar o número de colunas com auto-fit ou auto-fill. Os dois modos de repetição automática diferem na forma como lidam com faixas vazias; áreas nomeadas fornecem outra forma de descrever regiões maiores da página.

Compare repetição fixa e automática

.cards {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
}

repeat(3, ...) define três colunas independentemente do número de cartões. Um quarto item colocado automaticamente vai para a próxima linha; ele não aumenta a contagem de colunas. Isso difere da repetição automática, que calcula quantas faixas cabem. Veja Fundamentos de Grid: faixas, linhas e posicionamento.

.cards {
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 192px), 1fr));
}

auto-fit calcula quantas colunas caberão com o tamanho mínimo especificado. O primeiro valor de minmax é o mínimo, o segundo valor é o máximo, e 1fr divide o espaço restante. Aqui min(100%, 192px) garante que a largura mínima da coluna não seja maior que a do seu elemento pai. Fixar o mínimo das colunas em apenas 192px pode fazer com que até uma coluna ultrapasse o elemento pai quando o pai for mais estreito que 192px.

Para um contêiner de 800px, colunas mínimas de 192px e espaços de 16px, três colunas precisam de 608px, enquanto quatro precisam de 816px. Apenas três colunas cabem. Esse cálculo determina a contagem de colunas; a distribuição subsequente do espaço livre determina suas larguras finais. Textos longos ainda precisam de uma estratégia de quebra.

Compare auto-fill e auto-fit

valor Faixa repetida vazia após a colocação do item Tela grande com poucos itens
auto-fill Manter faixas vazios Espaço de coluna vazio restante
auto-fit Colapsar faixas de repetição sem itens As faixas ocupadas se expandem para o espaço disponível

Ambos os valores calculam inicialmente as colunas repetidas que podem ser alocadas neles. A diferença com o ajuste automático (auto-fit) está no processo de colapsar faixas repetidas vazias após a colocação. Se os itens preencherem todas as colunas, os dois valores podem parecer semelhantes, por isso faça os contêineres mais largos e tenha menos cartões ao comparar. Mesmo quando todos os cartões cabem em uma coluna em uma tela pequena, a diferença é difícil de perceber. Descrição de repeat() no MDN: repeat() e repetição automática .

Entenda o posicionamento automático e dense

Itens que não especificam uma posição são colocados por linha de acordo com o grid-auto-flow: row padrão. Mesmo que o item anterior ocupe uma grande área e um espaço vazio seja criado, a colocação padrão não retorna constantemente ao espaço vazio ao colocar o próximo item. Esse comportamento padrão facilita a compreensão da ordem HTML e da progressão visual.

grid-auto-flow: row dense pode preencher o espaço vazio na frente com pequenos itens atrás. Embora o espaço fique mais apertado, a ordem em que aparece na tela e a ordem do DOM (Document Object Model, modelo de objetos do documento) podem diferir. O posicionamento em CSS não reordena o HTML, portanto o foco do teclado e a ordem de leitura devem ser considerados juntos. Para etapas numeradas de forma significativa, registros cronológicos e entradas de formulário, manter a ordem é mais importante do que eliminar espaços em branco. Consulte MDN: grid-auto-flow e posicionamento automático.

Execute o exemplo de repetição automática

Salve o exemplo como grid-auto-repeat.html. A primeira seção tem dois cartões em um contêiner limitado a 800px. A segunda seção usa dois links ocupando duas colunas e dois ocupando uma coluna, deixando um espaço que permite comparar a colocação comum com dense.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>grid-auto-repeat.html</title>
  <style>
* { box-sizing: border-box; }
body { margin: 16px; font: 16px/1.6 sans-serif; color: #243447; }
h1 { font-size: 24px; } h2 { font-size: 20px; margin-top: 32px; }
a { color: #145f8f; } a:focus-visible { outline: 3px solid #b4470b; outline-offset: 3px; }
.cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 192px), 1fr));
 gap: 16px; width: min(100%, 800px); }
 .cards > div { min-width: 0; padding: 16px; background: #dceefa; overflow-wrap: anywhere; }
 .flow { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px;
 grid-auto-flow: row; max-width: 600px; margin-top: 16px; }
 .flow > a { padding: 12px; background: #e8f5de; }
 .flow > .wide { grid-column: span 2; }
  </style>
</head>
<body>
<h1>Comparing empty repeated columns</h1><div class="cards"><div>First card</div><div>Second card</div></div>
<h2>Default auto-placement</h2><div class="flow"><a class="wide" href="#result">1: two spaces</a><a class="wide" href="#result">2: two spaces</a><a href="#result">3: One space</a><a href="#result">4: one space</a></div>
<p id="result">This is the destination of the automatic-layout link.</p>
</body>
</html>
  1. Em uma tela larga, se a primeira seção tiver 800px, os dois cartões com auto-fit ocuparão 392px cada. Substituir apenas auto-fit por auto-fill preserva as três colunas, deixando as duas primeiras colunas de cartões com cerca de 256px e uma coluna vazia. Após a confirmação, restaure para auto-fit.
  2. Copie mais divs para a primeira seção para que fique com quatro. Três colunas estão preenchidas e um quarto cartão é colocado na próxima linha. Nessa condição, não há colunas repetidas vazias, o que reduz a diferença entre os dois valores. Após a prática, retorne aos dois cartões originais.
  3. Teste uma largura de contêiner menor que 192px. Se a janela não puder ser tão estreita, defina temporariamente width: 180px em .cards e remova essa declaração ao terminar. Graças a min(100%, 192px), uma coluna caberá em seu elemento pai. Alterar o mínimo para apenas 192px pode causar transbordamento em áreas mais estreitas. Após a comparação, a expressão original é restaurada.
  4. Verifique o espaço vazio após o link 1 e a localização do link 3 no .flow. Se você alterar apenas grid-auto-flow para row dense, o número 3 será colocado no espaço vazio anterior. A ordem visual passa a 1 → 3 → 2 → 4, mas com Tab a sequência do HTML continua 1 → 2 → 3 → 4. Retorne para row após a prática.

Defina regiões da página com áreas nomeadas

Ao invés de calcular os números de colunas e linhas separadamente, é mais fácil entender a intenção do layout da página expressando grandes seções com nomes como header, main, aside e footer. Cada string em grid-template-areas é uma linha, e os nomes separados por espaços dentro da string são células. O valor grid-area do filho deve corresponder ao seu nome para entrar nessa área. Como alterar a configuração da coluna com base na largura da tela é explicado em Media queries e pontos de quebra baseados no conteúdo.

Repetir o mesmo nome em várias células cria uma área retangular. As áreas não podem ter formato de L ou de ilha isolada. Cada linha deve ter o mesmo número de células, e as células que devem ficar em branco são indicadas com um ponto (.). Se uma declaração for inválida, o navegador não a respeitará, o que pode dar a impressão de posicionamento automático. Você pode verificar as condições de área válidas na descrição de grid-template-areas do MDN.

Salve o código abaixo como grid-areas.html. No desktop, o corpo e as informações adicionais são colocados lado a lado, e em telas de 640px ou menores, eles ficam em uma coluna. O HTML mantém main antes de aside em todos os tamanhos; a mudança visual não inverte a ordem de leitura.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>grid-areas.html</title>
  <style>
* { box-sizing: border-box; }
body { margin: 16px; font: 16px/1.6 sans-serif; color: #243447; }
h1 { font-size: 24px; } h2 { font-size: 20px; margin-top: 32px; }
a { color: #145f8f; } a:focus-visible { outline: 3px solid #b4470b; outline-offset: 3px; }
.page { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
 grid-template-areas: "header header" "main aside" "footer footer"; gap: 16px; max-width: 1000px; }
 .page > * { min-width: 0; padding: 20px; background: #dceefa; overflow-wrap: anywhere; }
 header { grid-area: header; } main { grid-area: main; } aside { grid-area: aside; } footer { grid-area: footer; }
 @media (max-width: 640px) {
 .page { grid-template-columns: minmax(0, 1fr); grid-template-areas: "header" "main" "aside" "footer"; }
 }
  </style>
</head>
<body>
<h1>Page area names</h1><div class="page"><header>Site title</header><main><h2>Main content</h2><p>This is the main content area. The HTML order keeps it first on mobile, too.</p></main><aside>Related information</aside><footer>Contact and site information</footer></div>
</body>
</html>
  1. Certifique-se de que o cabeçalho e o rodapé ocupem duas colunas em uma tela ampla. Se você reduzir a tela para 640px ou menos, header → main → aside → footer estarão em uma coluna. Veja por que você precisa alterar as definições de coluna e as strings de área juntas.
  2. Altere apenas a grid-area do aside para um nome diferente. A conexão entre a área aside reservada no template e o elemento real pode ser desconectada e não ser colocada no slot pretendido. Restaure o nome para aside.
  3. Se você alterar apenas o template da tela ampla para "header header" "header aside" "footer footer", o cabeçalho ficará em forma de L e a declaração grid-template-areas será inválida. Após confirmar a aplicação nas Ferramentas de Desenvolvedor, as três strings originais são restauradas.

Na prática, é mais fácil de manter se você separar a área para criar colunas com base no número de cartões e a área para nomear as seções da página. A repetição automática determina o número e a largura mínima, enquanto os nomes das regiões determinam a estrutura da página e os pontos de transição. Antes de tentar forçar os dois em uma única regra, decida qual problema cada contêiner está tentando resolver.