Layouts CSS e design responsivo

  1. 1 Noções básicas
    1. Qual modo de layout usar?
    2. Princípios de trabalho
  2. 2 Flexbox
  3. 3 Grade e subgrade
    1. Exemplo de código: grade e subgrade
  4. 4 Consultas de contêiner
    1. Exemplo de código: tipografia fluida usando unidades de consulta de contêiner
  5. 5 Sobreposições nativas, posicionamento de âncora e contextos de empilhamento
  6. 6 Rastreamento de overflow e estabilidade do layout
  7. 7 Mecânica da janela de visualização e distribuição de faixas
  8. 8 faixas de grade (também conhecidas como alvenaria)

1 Conceitos básicos

Sempre que possível, use o mecanismo de layout do navegador para melhorar o desempenho. Use o dimensionamento intrínseco, as propriedades lógicas e aspect-ratio antes de recorrer a dimensões fixas ou consultas de mídia complicadas.

1.1 Qual modo de layout usar?

Percorra a árvore de decisão de cima para baixo e pare na primeira correspondência. Os layouts podem ser aninhados uns nos outros, e cada decisão é baseada no caso de uso do contêiner.

  1. É uma linha OU coluna simples de itens? Use o flexbox: 1D, prioriza o conteúdo, que é distribuído ao longo de um único eixo.
  2. Um elemento aninhado precisa se alinhar com as faixas da grade do elemento pai? Use subgrid: 2D, prioriza as relações, herda as faixas pai para que os netos possam se alinhar entre os irmãos.
  3. É uma estrutura complexa de página ou componente com linhas E colunas? Use grid: 2D, prioriza o layout, você define o esqueleto e o conteúdo o preenche.
  4. O conteúdo é um fluxo longo de prosa que precisa ser dividido em colunas equilibradas? Use várias colunas: fluxo 1D, estilo jornal.
  5. Os itens têm alturas variadas e precisam ser embalados de forma compacta? Use grid com grid-auto-flow: dense hoje. Use o masonry nativo (também conhecido como "faixas de grade") somente quando ele for enviado no seu destino Baseline (consulte §8).
  6. Um elemento precisa flutuar acima da página e permanecer espacialmente vinculado a um acionador, mesmo em limites do DOM ou contextos de empilhamento? Use o posicionamento de âncora: anchor-name no acionador, position-anchor na sobreposição (consulte o §5).

1.2 Princípios de trabalho

  • Use propriedades lógicas (inline-size, block-size, margin-inline, padding-block, inset-inline-start) para dimensões e espaçamento de layout. Consulte CSS: Modern Architecture para uma cobertura completa.
  • Aplique o modelo mental de conteúdo primeiro x layout primeiro: flexbox quando os itens ditam o fluxo, grade quando você define o esqueleto primeiro.
  • Use as abreviações de place-* (place-content, place-items, place-self) para alinhar os dois eixos em uma única declaração.
  • Use o dimensionamento intrínseco (min-content, max-content, fit-content()) e as faixas flexíveis (fr, minmax()) antes de width/height fixos: menos consultas de mídia, layouts mais resilientes.
  • NÃO use overflow: hidden para mascarar problemas de layout. Corrija-os na origem. Por exemplo, alguns elementos substituídos, como <canvas>, <img>, <svg>, <video> e <iframe>, usam display: inline por padrão, o que pode adicionar um espaço em determinados layouts. Em vez de cortar o espaço com overflow, remova-o aplicando um valor de exibição externa de bloco (por exemplo, display: block, grid, flex etc.).
  • Use aspect-ratio para reservar espaço para mídia e evitar mudanças de layout antes que os recursos sejam carregados.
.sidebar       { inline-size: max-content; }    /* Size to longest unbreakable token. */
.main-content  { inline-size: fit-content; }    /* Grow to available space, no further. */
.media         { aspect-ratio: 16 / 9; inline-size: 100%; block-size: auto; }
body.centered  { display: grid; place-content: center; min-block-size: 100dvb; }

Para calc-size() e dimensionamento intrínseco com restrições, consulte Calcular com tamanhos intrínsecos.

2 Flexbox

Layout unidimensional: os itens fluem ao longo de um único eixo principal com alinhamento no eixo transversal. Use-o para barras de navegação, barras de ferramentas, linhas de itens e qualquer distribuição de linha ou coluna única.

O que fazer:

  • Estabeleça um contexto com display: flex e defina o eixo principal com flex-direction (padrão row).
  • Use flex-wrap: wrap sempre que houver possibilidade de transbordamento. nowrap sem overflow: auto/hidden vai transbordar em janelas de visualização estreitas.
  • Camada flex-wrap: balance após flex-wrap: wrap em linhas agrupadas de itens compactos (como nuvens de tags, pílulas de filtro, grupos de botões ou links de navegação) para distribuir os itens de maneira uniforme entre as linhas e evitar um único item órfão na linha final. Os navegadores sem suporte usam wrap.
  • Use a abreviação <grow> <shrink> <basis> de flex (por exemplo, flex: 1 1 250px) em itens em vez de definir flex-grow/flex-shrink/flex-basis individualmente.
  • Use gap (ou a forma completa row-gap/column-gap) para o espaçamento entre itens em vez de margens filhas.
  • Prefixe o alinhamento posicional com safe (por exemplo, align-items: safe center) para que o conteúdo focalizável não seja cortado quando o contêiner for mais estreito que o conteúdo.
  • Envie um único item para a extremidade do eixo principal com margin-inline-start: auto (ou margin-block-start: auto). Essa é a saída de emergência padrão.
  • Substitua o alinhamento entre eixos por item com align-self.
  • Use align-items para centralizar todos os itens no eixo transversal. Use margin: auto em um único item para centralizá-lo nos dois eixos de forma independente. Use align-content somente quando o contêiner tiver quebra de linha e espaço extra entre as linhas.
  • Defina min-inline-size: 0 (ou min-width: 0) em itens flexíveis que contêm conteúdo longo que não pode ser quebrado (URLs, código, strings longas). Por padrão, os itens flexíveis não diminuem abaixo do tamanho do conteúdo, o que causa estouro.

Não faça o seguinte:

  • Não use justify-self em itens flexíveis. Ele só funciona em layouts de grade, bloco e posicionamento absoluto. Use margens automáticas.
  • Não use order ou flex-direction: *-reverse para reordenar o conteúdo interativo. Eles mudam apenas a ordem visual. A ordem do DOM ainda determina o foco sequencial, então o fluxo de tabulação do teclado não vai corresponder ao que o usuário vê.
  • Não confunda space-around (metade do espaçamento nas extremidades) com space-evenly (espaçamentos iguais antes, entre e depois).
  • Não se esqueça da inversão de eixo: quando flex-direction: column, justify-content se alinha no eixo de bloco e align-items se alinha no eixo inline, o oposto do padrão.
  • Não dimensione o contêiner e os filhos para que eles se preencham, porque isso é uma fonte comum de estouro e resultados surpreendentes. Defina um tamanho para um dos lados.
  • Não defina flex-basis e width/inline-size no mesmo item. flex-basis tem precedência em um contexto flexível, e width é ignorado. Use flex-basis (ou a abreviação flex) como a única fonte de verdade para dimensionar itens flexíveis.
.card-grid        { display: flex; flex-flow: row wrap; gap: 1rem; }
.card-item        { flex: 1 1 250px; }                  /* grow, shrink, basis */
.card-item-action { margin-inline-start: auto; }        /* Push to main-axis end. */
.toolbar          { display: flex; align-items: safe center; }
.tag-list         { display: flex; flex-wrap: wrap; flex-wrap: balance; gap: 0.5rem; }

3 Grade e subgrade

Layout bidimensional: defina linhas E colunas explicitamente ou deixe que o mecanismo as derive. A subgrade permite que uma grade aninhada herde as faixas da grade pai para que os netos se alinhem entre os irmãos.

Como escolher os recursos da grade:

  • Você sabe exatamente de quantas colunas precisa?
    • Sim: use faixas explícitas (grid-template-columns: 200px 1fr, repeat(3, 1fr) etc.)
    • As colunas precisam de tamanhos diferentes (barra lateral + principal, cabeçalho abrangendo tudo)? → use grid-template-areas para regiões nomeadas e legíveis
    • Todas as colunas são uniformes ou posicionadas apenas pelo número da linha? → use repeat(N, ...) ou linhas nomeadas
    • Não (responsivo, contagem de itens desconhecida): use repeat(auto-fit, minmax(min, 1fr)).
    • Os itens na última linha devem ser esticados para preencher o espaço restante? → auto-fit
    • As faixas vazias da última linha devem manter o tamanho mínimo (preservando os espaços fantasmas da coluna)? → auto-fill
  • Você precisa colocar um item em um local específico?
    • Sim: use grid-column: <start> / <end> ou grid-area: <name>
    • Não (apenas abrangendo várias faixas, a posição do fluxo não importa): use grid-column: span <n>
  • Os elementos filhos precisam herdar os tamanhos de faixa da grade pai (alinhamento de borda irregular entre irmãos)?
    • Sim: use a subgrade no eixo afetado.
    • O número de filhos por célula é variável? → subgrade apenas um eixo; use grid-auto-rows/grid-auto-columns para o outro
    • A contagem de filhos é fixa? → subgrid em ambos os eixos é aceitável
    • Não: grade padrão, sem necessidade de subgrade

O que fazer:

  • Estabeleça um contexto com display: grid.
  • Use grid-template-areas para layouts complexos no nível da página. Os nomes das áreas são autodocumentados, e a declaração pode ser alinhada em linhas e colunas para facilitar a leitura.
  • Use repeat(auto-fit, minmax(200px, 1fr)) para grades de cards responsivas que esticam as faixas preenchidas para completar a linha ou auto-fill para preservar as faixas repetidas vazias no tamanho mínimo.
  • Use fr para distribuição proporcional de faixas e minmax(min, max) para faixas flexíveis, mas limitadas.
  • Posicione itens com grid-column: span <n> para dimensionar entre faixas, grid-column: <start> / <end> para colocar em linhas específicas ou grid-area: <name> para regiões nomeadas.
  • Use a subgrade (grid-template-columns: subgrid ou grid-template-rows: subgrid) para resolver o problema de "borda irregular" em listas de cards. Elementos internos, como títulos, metadados e CTAs, se alinham entre os irmãos.
  • Combine uma declaração de subgrade com uma declaração grid-template-rows/-columns explícita anterior como um substituto de mesma cascata para navegadores mais antigos.

Não faça o seguinte:

  • Não espere que o tamanho da faixa auto-fit/auto-fill venha do conteúdo do item. Ele vem do argumento de tamanho repeat().
  • Não use grid-auto-flow: dense em conteúdo interativo. Ele agrupa os itens de forma eficiente, mas os reordena visualmente, quebrando o fluxo de tabulação do teclado na ordem do DOM.
  • Não aplique a subgrade aos dois eixos quando a contagem de filhos for variável. Os extras vão para a última faixa. Use grid-auto-rows/grid-auto-columns para o eixo implícito.
  • Não confunda justify-items/align-items (alinha o conteúdo do item na faixa) com justify-content/align-content (alinha as faixas da grade no contêiner). Usar o errado não tem efeito.
  • Não use repeat(auto-fit/auto-fill, ...) sem um inline-size definido no contêiner. Dentro de display: inline-grid ou de um item flexível sem tamanho, o contêiner não tem largura para dividir, o que torna as contagens de faixas imprevisíveis.

3.1 Exemplo de código: grade e subgrade

Shell da página: <main class="page-layout"> contém <header>, <aside>, um <section class="card-grid"> com <div class="card"> filhos e <footer>.

/* Align grid-template-areas in rows and columns for readability. */
.page-layout {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-areas:
    "header  header  header"
    "sidebar main    main"
    "footer  footer  footer";
  gap: 1.5rem;
}

header  { grid-area: header; }
aside   { grid-area: sidebar; }
footer  { grid-area: footer; }

.card-grid {
  grid-area: main;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  grid-template-rows: auto 1fr; /* title block, body block */
  gap: 1rem;
}

.card {
  grid-row: span 2;
  display: grid;
  /* Same-cascade fallback: ignored when subgrid is supported. */
  grid-template-rows: auto 1fr;
  grid-template-rows: subgrid;
}

4 Consultas de contêiner

Consulte o tamanho (ou estilo computado) de um contêiner ancestral em vez da janela de visualização. Modelo mental: consultas de contêiner = contexto do componente; consultas de mídia = layout global da página e preferências do usuário (prefers-color-scheme, prefers-reduced-motion).

O que fazer:

  • Estabeleça um contexto de contenção com container-type: inline-size (consultas somente de largura) ou container-type: size (ambos os eixos) em um wrapper antes que os descendentes possam ser consultados.
  • Nomeie os contêineres com container-name (ou a abreviação container: container: card / inline-size) quando contextos aninhados puderem entrar em conflito.
  • Inclua unidades de consulta de contêiner no cálculo do tipo e do espaçamento fluidos: cqi/cqb (inline/bloco lógico), cqw/cqh (físico), cqmin/cqmax.
  • Dê ao contêiner um block-size definido sempre que container-type: size for usado. Sem isso, os descendentes vão ser recolhidos porque a contenção de tamanho força o contêiner a ignorar o conteúdo.

Não faça o seguinte:

  • Não use block-size como um valor de container-type, porque ele não é válido. Use size para os dois eixos.
  • Não espere que o tamanho intrínseco dos filhos influencie o contêiner depois de declarar container-type. O contêiner é calculado como se não tivesse filhos quando a contenção está ativa.
  • Não use unidades de consulta de contêiner em descendentes de um ancestral não qualificado. Elas vão usar a janela de visualização pequena (svw/svh).

4.1 Exemplo de código: tipografia fluida usando unidades de consulta de contêiner

.card-wrapper {
  container: card / inline-size; /* shorthand for container-name / container-type */
}

@container card (inline-size > 400px) {
  .content {
    display: flex;
    gap: 2rem;
  }
}

.title {
  /* Fluid type bound to the container width, not the viewport. */
  font-size: clamp(1rem, 4cqi, 2rem);
}

Para padrões de estilo responsivos orientados por componentes, consulte Estilo que considera o tamanho e Escalonamento fluido.

5 Sobreposições nativas, posicionamento de âncora e contextos de empilhamento

Quando usar cada primitiva de sobreposição:

  • Use popover para IU temporária e não modal (flyouts, toasts, dicas) que fica na camada superior, sem necessidade de gerenciamento de z-index.
  • Use <dialog> com .showModal() para interações modais que exigem captura de foco e um plano de fundo inerte.
  • Não combine popover e .showModal() no mesmo elemento, porque eles são estados de execução mutuamente exclusivos.

Posicionamento de âncora (layout espacial de sobreposições):

  • Use position-area (ou anchor() em inserções) e anchor-size() para posicionar e dimensionar uma sobreposição em relação ao acionador.
  • Use position-try-fallbacks: flip-block (ou flip-inline) para permitir que o navegador reposicione quando a sobreposição ultrapassar a janela de visualização.
  • Não misture palavras-chave físicas e lógicas em um único valor position-area. Escolha um sistema de coordenadas.
  • Detecte recursos com @supports (anchor-name: --x) e forneça um substituto de posição absoluta.

Para detalhes completos de implementação, estratégias de polyfill e referência de valor de popover, consulte Controle declarativo de caixas de diálogo e pop-overs e Dicas de ferramentas que consideram a posição. Para o posicionamento de âncora aplicado a menus suspensos, menus flutuantes e indicadores de guia, consulte Menus suspensos que consideram a janela de visualização e Sublinhado da guia de posicionamento de âncora.

6 Rastreamento de overflow e estabilidade do layout

Gerencie mudanças de layout, barras de rolagem e cortes de forma previsível.

O que fazer:

  • Use overflow: auto para que as barras de rolagem apareçam apenas quando o conteúdo realmente ultrapassar o limite.
  • Use overflow: clip para cortar conteúdo sem estabelecer um contêiner de rolagem. Ative o transbordamento com overflow-clip-margin.
  • Use scrollbar-gutter: stable para reservar espaço para barras de rolagem e evitar mudanças de layout quando o conteúdo aumenta.
  • Use overscroll-behavior: contain (ou none) em regiões de rolagem aninhadas (como barras laterais, modais e listas) para impedir que as cadeias de rolagem se propaguem para a página, ou overscroll-behavior: chain em wrappers de rolagem intermediários (como faixas de deslizar para revelar) quando o excesso de rolagem precisa ser propagado para um scroller ancestral sem acionar um efeito de elástico local.
  • Use a tríade -webkit-line-clamp + display: -webkit-box + -webkit-box-orient: vertical para truncamento de várias linhas. Apesar do prefixo, esse padrão é totalmente especificado e não foi descontinuado. Declare a abreviação line-clamp sem prefixo ao lado dela. Os navegadores que ainda não são compatíveis com ela ignoram a propriedade sem causar danos. Não faça o seguinte:

  • Não use overflow: scroll quando auto for suficiente. scroll força as barras de rolagem mesmo quando não há nada para rolar.

  • Não use overflow: hidden quando quiser apenas cortar. O hidden estabelece um contêiner de rolagem que pode ser rolado de forma programática.

.scrollable-list {
  max-block-size: 400px;
  overflow-y: auto;
  scrollbar-gutter: stable;       /* Reserve scrollbar space. */
  overscroll-behavior: contain;   /* No scroll chaining into the page. */
}

.snippet {
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  line-clamp: 3;                  /* Ignored where unsupported. */
  overflow: clip;
}

Para saber mais sobre overflow: clip e overflow-clip-margin, consulte Controle de corte de estouro. Para transferência de rolagem aninhada com overscroll-behavior: chain na interface de deslizar para revelar, consulte Deslizar para revelar. Para saber mais sobre a cor, o tamanho e o tema da barra de rolagem, consulte Personalizar a cor ou a espessura de uma barra de rolagem, Modo escuro e Adaptar a barra de rolagem às preferências de alto contraste.

7 Mecânica da janela de visualização e distribuição de faixas

  • Use dvh/dvw para contêineres de layout para dispositivos móveis que precisam considerar a mudança na interface do navegador (recolhimento/expansão da barra de URL).
  • Não use 100vw para layout de largura total, porque ele ignora a largura da barra de rolagem e causa estouro horizontal. Use 100%, 100dvw ou 100svw.

Para o ponto de entrada do design responsivo (unidades de janela de visualização dinâmica, reserva de espaço para mídia, tipografia fluida), consulte Design responsivo.

8 faixas de grade (também conhecidas como masonry)

A especificação está em desenvolvimento com o nome "faixas de grade" (por exemplo, display: grid-lanes), enquanto os protótipos experimentais anteriores usavam grid-template-rows: masonry.

O que fazer:

  • Use a grade com grid-auto-flow: dense para compactação hoje, aceitando que a ordem do DOM pode não corresponder à ordem visual.
  • Use várias colunas (columns: 3; column-gap: 1rem) para um fluxo semelhante a alvenaria com muito conteúdo quando os itens forem fragmentos de documentos, em vez de cards de peso igual.
  • Trate grid-template-rows: masonry apenas como um aprimoramento progressivo: use @supports para detectar recursos.

Não faça o seguinte:

  • Não envie grid-template-rows: masonry como um requisito rígido até que sua meta de referência seja alcançada.
.gallery       { columns: 3 200px; column-gap: 1rem; }
.gallery > *   { break-inside: avoid; margin-block-end: 1rem; }

@supports (grid-template-rows: masonry) {
  .gallery {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    grid-template-rows: masonry;
    gap: 1rem;
    columns: unset;
  }
}