Pular para o conteúdo
Cursos

DevClub

LógicaFront-endBack-endMobile

IA Club

IA na prática
Estudar programaçãoEstudar IA
LiçãoIniciantecódigo testado

Flexbox CSS: alinhe e distribua elementos com clareza

Aprenda container, itens, eixos, gap, flex e wrap criando uma prateleira de livros, com posições e transbordamento medidos no navegador.

Rodolfo Mori6 min de leitura

Flexbox organiza os filhos diretos de um contêiner em uma linha ou coluna e distribui o espaço disponível entre eles. Com display: flex, você consegue alinhar cartões, criar menus e permitir que itens cresçam, encolham ou quebrem de linha sem calcular a posição de cada um na mão.

Nesta lição, três livros vão ocupar uma prateleira de 600 pixels. As posições, os tamanhos e o transbordamento foram medidos no Google Chrome 151.0.7922.170. Antes de distribuir caixas, vale entender como o box model calcula a largura real, porque padding e border também consomem o espaço que o Flexbox precisa repartir.

A prateleira define a direção; os livros ocupam o espaço

Imagine uma prateleira com três livros. A prateleira é o flex container; os livros colocados diretamente nela são os flex items. O comprimento da prateleira representa o main axis, ou eixo principal. A direção da altura é o cross axis, ou eixo transversal. O trecho que sobra depois de acomodar os livros é o espaço livre que o Flexbox pode distribuir.

O mapeamento volta ao CSS assim: display: flex cria o container, flex-direction escolhe a direção do eixo principal, justify-content trabalha nesse eixo e align-items trabalha no eixo transversal. A analogia tem limite: itens flex podem crescer e encolher, e o eixo pode virar uma coluna. Além disso, quando existe flex-wrap, cada linha distribui seu próprio espaço; não é uma prateleira física contínua.

Comece com uma estrutura sem elementos extras entre o container e os itens:

html
<div class="prateleira" id="prateleira">
  <article class="livro">Livro 1</article>
  <article class="livro">Livro 2</article>
  <article class="livro">Livro 3</article>
</div>

Os três article são filhos diretos e, portanto, viram flex items. Um título dentro de um article não vira item do container externo; ele participa do layout interno do próprio cartão. Essa distinção evita aplicar flex no lugar errado.

O primeiro display flex e seus padrões

Ative Flexbox no pai. Sem outras propriedades, o eixo principal usa row, os itens começam em flex-start, podem encolher e não quebram para outra linha.

css
.prateleira {
  display: flex;
  width: 600px;
}

.livro {
  border: 2px solid currentColor;
}

Quando você muda flex-direction para column, o eixo principal deixa de percorrer a linha e passa a percorrer a coluna:

css
.prateleira {
  display: flex;
  flex-direction: column;
}

Por isso, memorize os termos principal e transversal, não “horizontal” e “vertical”. Com row, justify-content costuma mover no sentido horizontal; com column, a mesma propriedade trabalha no sentido vertical.

Também existem row-reverse e column-reverse. Eles mudam a apresentação, mas não alteram a ordem dos elementos no HTML. Leitores de tela e navegação por Tab continuam seguindo a ordem do documento. Use reversão para uma necessidade visual, não para consertar uma estrutura semântica fora de ordem.

Distribuir exige saber quanto espaço sobrou

Agora vamos fixar uma medida previsível para cada livro. O shorthand flex: 0 0 100px reúne flex-grow, flex-shrink e flex-basis: não crescer, não encolher e começar com 100 pixels.

css
.prateleira {
  box-sizing: border-box;
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 600px;
  height: 140px;
  padding: 20px;
}

.prateleira > .livro {
  box-sizing: border-box;
  flex: 0 0 100px;
  height: 60px;
}

A largura interna disponível é 560: os 600 pixels incluem 20 de padding em cada lado. Os três livros consomem 300, então sobram 260. Com space-between, esse espaço é repartido nos dois intervalos: 130 pixels em cada um.

O teste leu a posição de cada livro em relação à borda esquerda e superior do container:

js
const prateleira = document.querySelector('#prateleira');
const base = prateleira.getBoundingClientRect();

const posicoes = [...prateleira.children].map((livro) => {
  const caixa = livro.getBoundingClientRect();
  return {
    x: caixa.x - base.x,
    y: caixa.y - base.y,
    width: caixa.width,
    height: caixa.height,
  };
});

console.table(posicoes);
livro 1: x 20, y 40, width 100, height 60 livro 2: x 250, y 40, width 100, height 60 livro 3: x 480, y 40, width 100, height 60

Os x confirmam os intervalos: o primeiro começa depois dos 20 pixels de padding; o segundo começa em 20 + 100 + 130 = 250; o terceiro, em 480. O y: 40 também tem explicação: sobram 80 pixels na altura interna, e align-items: center deixa 40 acima do livro.

Se justify-content parece não fazer nada, pergunte primeiro: existe espaço livre no eixo principal? Um item com width: 100% pode consumir tudo e não deixar nada para distribuir. E não tente trocar por justify-items: essa propriedade é ignorada no layout Flexbox.

Gap é a distância; justify-content distribui a sobra

gap cria uma distância estável entre itens. justify-content distribui o espaço que sobrou depois de considerar tamanhos e gaps. São responsabilidades diferentes.

css
.lista-produtos {
  display: flex;
  gap: 16px;
  justify-content: flex-start;
}

Use gap quando o requisito diz “mantenha 16 pixels entre os cartões”. Use space-between quando diz “encoste o primeiro e o último nas pontas e reparta a sobra entre eles”. Num menu, essa diferença aparece quando a largura da tela muda: o gap permanece; a sobra é recalculada.

O margin ainda funciona em flex items, inclusive margin-inline-start: auto para consumir o espaço livre antes de um item. Mas, quando a distância pertence ao conjunto inteiro, gap deixa essa intenção visível no container e evita margens especiais no primeiro ou no último cartão.

Crescer, encolher e usar uma base

O shorthand flex responde como o item participa quando há sobra ou falta de espaço:

css
.produto-card {
  flex: 1 1 14rem;
  min-width: 0;
}

O primeiro 1 é flex-grow: o item pode receber uma parte da sobra. O segundo é flex-shrink: ele pode encolher quando faltar espaço. 14rem é flex-basis, o tamanho inicial usado na negociação. Se três cartões usam a mesma configuração, eles dividem a sobra com a mesma proporção.

min-width: 0 merece atenção em cards com textos longos. Flex items têm um tamanho mínimo automático baseado no conteúdo; uma URL ou palavra sem quebra pode impedir o encolhimento. Zerar o mínimo permite que as regras de quebra do conteúdo façam seu trabalho. Isso não significa colocar min-width: 0 em tudo, mas reconhecer o padrão quando um item isolado insiste em transbordar.

Wrap cria novas linhas de itens inteiros

Uma coleção de 320 pixels recebe três livros de 140 e um gap de 16. Dois cabem na primeira linha, porque 140 + 16 + 140 = 296; o terceiro precisa ir para a linha seguinte.

css
.colecao {
  display: flex;
  flex-wrap: wrap;
  width: 320px;
  gap: 16px;
}

.colecao > .livro {
  box-sizing: border-box;
  flex: 0 0 140px;
  height: 60px;
}

O navegador confirmou as coordenadas relativas dos três itens:

js
const colecao = document.querySelector('.colecao');
const origem = colecao.getBoundingClientRect();

const posicoes = [...colecao.children].map((item) => {
  const caixa = item.getBoundingClientRect();
  return { x: caixa.x - origem.x, y: caixa.y - origem.y };
});

console.table(posicoes);
livro 1: x 0, y 0 livro 2: x 156, y 0 livro 3: x 0, y 76

O segundo começa em 156 porque há 140 pixels de item e 16 de gap. O terceiro volta ao começo em x: 0 e desce para y: 76: 60 de altura mais 16 de gap. Flexbox resolveu uma dimensão por linha; ele não criou colunas compartilhadas entre todas as linhas. Se o alinhamento em duas dimensões for requisito, CSS Grid tende a representar melhor o problema.

O erro: pedir três livros onde só cabem dois

Retire o flex-wrap ou deixe o valor inicial nowrap, mantendo os itens sem permissão para encolher:

css
.colecao-sem-quebra {
  display: flex;
  flex-wrap: nowrap;
  width: 320px;
  gap: 16px;
}

.colecao-sem-quebra > .livro {
  flex: 0 0 140px;
}

A conta pede 452 pixels: três vezes 140, mais dois gaps de 16. Como o container oferece 320, os itens avançam 132 pixels além dele. Esta medição reproduz o defeito:

js
const lista = document.querySelector('.colecao-sem-quebra');

console.log('largura disponível:', lista.clientWidth);
console.log('largura necessária:', lista.scrollWidth);
console.log('excesso:', lista.scrollWidth - lista.clientWidth);
largura disponível: 320 largura necessária: 452 excesso: 132

A correção depende do requisito. Se os cartões devem manter 140 pixels, permita a quebra:

css
.colecao-sem-quebra {
  flex-wrap: wrap;
}

Se devem permanecer na mesma linha, permita encolhimento ou escolha uma base menor. Se a fileira representa uma galeria horizontal intencional, mantenha nowrap e use overflow-x: auto com controles acessíveis. Não existe uma propriedade universal; existe uma decisão de produto expressa no CSS.

Sua missão: transformar uma lista em menu responsivo

Crie um menu que começa empilhado em telas estreitas e vira linha a partir de 640 pixels. O HTML deve continuar na ordem lógica de leitura:

html
<nav aria-label="Categorias da livraria">
  <ul class="menu">
    <li><a href="#romance">Romance</a></li>
    <li><a href="#tecnologia">Tecnologia</a></li>
    <li><a href="#biografias">Biografias</a></li>
  </ul>
</nav>
css
.menu {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 0;
  list-style: none;
}

@media (min-width: 640px) {
  .menu {
    flex-direction: row;
    align-items: center;
  }
}

O critério de sucesso é verificável: a 639 pixels, os três itens devem ter coordenadas y diferentes; a 640 pixels, devem compartilhar o mesmo y. Navegue também com Tab e confirme que a sequência continua Romance, Tecnologia e Biografias — nenhuma propriedade visual deve inverter a ordem semântica.

Se uma declaração de Flexbox não chega ao container, revise seletores e cascata. Se ela chega, mas aparece riscada, investigue a especificidade da regra. Em projetos React, o mesmo mecanismo continua valendo; o que muda é como a folha entra no componente, assunto de CSS no React.

  • css
  • flexbox
  • layout
  • alinhamento
  • responsividade

Perguntas frequentes

Flexbox serve para linha e para coluna?
Sim. flex-direction define o eixo principal como row ou column. As propriedades de alinhamento acompanham esse eixo, por isso justify-content nem sempre significa alinhamento horizontal.
Qual é a diferença entre justify-content e align-items?
justify-content distribui o espaço livre no eixo principal. align-items posiciona os itens no eixo transversal. Com row, normalmente são os eixos horizontal e vertical; com column, essa leitura se inverte.
Quando devo usar Flexbox e quando devo usar Grid?
Flexbox organiza uma dimensão por vez, uma linha ou uma coluna. Grid é indicado quando linhas e colunas precisam ser planejadas juntas. É comum usar Grid na estrutura da página e Flexbox dentro de um componente.
Por que flex-wrap não quebra palavras compridas?
flex-wrap cria novas linhas para itens flex inteiros. O texto dentro de um item segue outras regras; use overflow-wrap ou min-width 0 conforme o problema, sem confundir a caixa com o conteúdo dela.

Dúvidas e comentários

Travou em algum passo? Pergunte aqui — a equipe e outros alunos respondem.

Todo o código deste artigo foi executado em Google Chrome 151.0.7922.170, e as saídas exibidas são as reais — como produzimos este conteúdo.

Fontes consultadas

  1. MDN — Basic concepts of flexbox — developer.mozilla.org
  2. MDN — Aligning items in a flex container — developer.mozilla.org
  3. MDN — flex — developer.mozilla.org
  4. CSS Flexible Box Layout Module Level 1 — W3C — w3.org

Continue por aqui