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>
O 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;
}
O 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.
A 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;
}
O 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.
A diferença entre “footer no final do conteúdo” e “footer sticky”
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
Por que o footer fica no meio da página quando o conteúdo é curto?
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.
Como fixar o footer sem que ele cubra o conteúdo?
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.














