Como deixar o footer sempre no final da página com CSS

O footer flutua no meio da tela quando a página tem pouco conteúdo — como uma página de contato, 404 ou termos de uso. O problema não está no footer em si: está em como o body se comporta.

Por padrão, o body tem apenas a altura do seu conteúdo. Se o conteúdo ocupa 300px numa tela de 800px de altura, o footer aparece em 300px, não em 800px.

A solução: fazer o body ocupar no mínimo 100% da altura da janela e expandir o conteúdo principal para preencher o espaço restante.

Existem três abordagens modernas, cada uma com seus casos de uso:

Método 1: Flexbox no body (mais usado, recomendado)

A abordagem mais limpa e amplamente suportada:

body {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  margin: 0;
}

main {
  flex: 1; /* expande para ocupar todo o espaço disponível */
}

footer {
  /* nenhuma propriedade especial necessária */
}

HTML estrutural mínimo:

<!DOCTYPE html>
<html lang="pt-BR">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Minha página</title>
</head>
<body>
  <header>Cabeçalho</header>
  <main>Conteúdo principal</main>
  <footer>Rodapé</footer>
</body>
</html>

flex: 1 no main faz com que ele ocupe todo o espaço vertical disponível entre o header e o footer. O footer fica naturalmente empurrado para o final.

Por que min-height: 100vh e não height: 100vh? Com height: 100vh, se o conteúdo for maior que a tela, a página não cresce — o conteúdo transborda ou fica escondido. Com min-height, a página se expande quando necessário e ocupa pelo menos o tamanho da janela.

Método 2: CSS Grid (moderno, mais semântico)

Com CSS Grid, a estrutura fica ainda mais explícita:

body {
  display: grid;
  grid-template-rows: auto 1fr auto; /* header, conteúdo, footer */
  min-height: 100vh;
  margin: 0;
}

1fr no grid-template-rows faz o conteúdo principal (main) ocupar todo o espaço disponível entre o header (auto) e o footer (auto). É a abordagem mais clara semanticamente porque você define explicitamente que existem três áreas verticais.

documentação MDN sobre CSS Grid Layout tem referência completa sobre como fr e auto interagem.

Método 3: min-height com calc (quando não pode mexer no body)

Quando o body tem estilos existentes que não podem ser alterados (em temas WordPress, por exemplo), a abordagem com calc no elemento de conteúdo é a mais segura:

.conteudo {
  min-height: calc(100vh - 80px); /* 80px = altura do footer */
}

footer {
  height: 80px;
}

calc(100vh - 80px) garante que o conteúdo sempre ocupe a altura da janela menos o espaço do footer. O footer fica no final porque o conteúdo preenche o espaço acima dele.

Limitação: se o footer tiver altura variável (ex: footer responsivo com mais linhas no mobile), o cálculo fica impreciso. Prefira o método Flexbox nesses casos.

O problema do 100vh no mobile iOS

Em navegadores mobile, especialmente no Safari do iOS, 100vh inclui a barra de endereços e a barra inferior do browser na altura calculada. Isso faz com que 100vh seja maior do que a área visível, gerando scroll inesperado.

A solução moderna é usar 100dvh (dynamic viewport height), que recalcula com base no espaço realmente visível:

body {
  min-height: 100dvh; /* recalcula quando a barra do browser some/aparece */
}

Suporte: 100dvh é suportado em Chrome 108+, Safari 15.4+ e Firefox 101+. Para projetos que precisam suportar navegadores mais antigos, use 100vh como fallback:

body {
  min-height: 100vh; /* fallback */
  min-height: 100dvh; /* sobrescreve em browsers compatíveis */
}

Verifique a compatibilidade atualizada na tabela de suporte do Can I Use para viewport units.

Footer no final do conteúdo (o que este artigo cobre): o footer aparece depois de todo o conteúdo, nunca antes. Em páginas longas fica na base do scroll; em páginas curtas fica na base da tela.

Footer sticky ou fixed: o footer fica sempre visível na tela, mesmo quando o usuário rola a página. Isso usa position: fixed; bottom: 0 e é um padrão diferente, menos comum para rodapés.

/* Footer sticky — SEMPRE visível, mesmo rolando */
footer {
  position: fixed;
  bottom: 0;
  left: 0;
  width: 100%;
}

/* Problema: o footer fixo fica sobre o conteúdo */
/* Solução: adicionar padding-bottom no body */
body {
  padding-bottom: 80px; /* mesma altura do footer fixo */
}

O footer fixo é usado principalmente em barras de ação mobile (botão “Adicionar ao carrinho”, chat, etc.), não em rodapés de site completos.

Se você está construindo um site no WordPress com Elementor e quer controlar o footer visualmente, o processo está descrito em como criar um site com WordPress do zero.

Perguntas frequentes

Porque o body só tem a altura do conteúdo por padrão. Se o conteúdo ocupa 300px numa janela de 800px, o footer aparece em 300px. A solução é adicionar min-height: 100vh ao body com display: flex; flex-direction: column e flex: 1 no conteúdo principal.

Qual a diferença entre 100vh e 100dvh?

100vh corresponde à altura do viewport incluindo a barra do browser, o que pode causar scroll inesperado em mobile iOS. 100dvh (dynamic viewport height) recalcula com base no espaço visível real. Para novos projetos, prefira 100dvh com 100vh como fallback.

Use position: fixed; bottom: 0 no footer e adicione padding-bottom ao body com o mesmo valor da altura do footer. Isso mantém o footer sempre visível e empurra o conteúdo para não ficar atrás dele.

O método Flexbox no body quebra algum estilo existente?

Pode sim, se outros elementos do body dependem do comportamento de bloco padrão. Teste sempre em páginas existentes. Se houver conflitos, use a abordagem de min-height: calc(100vh - altura_do_footer) no conteúdo principal, que não afeta o body.

Funciona com WordPress e Elementor?

Depende do tema. Em temas como Astra ou Hello Elementor, adicionar display: flex; flex-direction: column; min-height: 100vh ao body via CSS personalizado geralmente funciona. Se o tema usa estrutura diferente, pode ser necessário adaptar os seletores.

O que é HTML
Picture of Sara Lima
Sara Lima

Criadora do Meu Site Web e trabalha com criação de sites, WordPress e Elementor há mais de 8 anos. Jornalista por formação, une escrita e tecnologia para criar conteúdo prático sobre desenvolvimento web acessível a qualquer pessoa.

Últimos Posts