CSS position: demo de static, relative, absolute, fixed e sticky | We.Inc
Alterne um elemento entre static, relative, absolute, fixed e sticky dentro de uma demo com rolagem. Containing blocks, inset, solução de problemas do sticky e centralização explicados.
A propriedade position escolhe como um elemento é posicionado. static é o fluxo normal. relative o desloca um pouco, mantendo o seu espaço. absolute o tira do fluxo e o posiciona em relação ao ancestral posicionado mais próximo. fixed o prende ao viewport. sticky rola normalmente até atingir um limite como top: 0 e então fica parado ali.
Os cinco valores
Valor
Fica no fluxo?
Posicionado em relação a
Fica no fluxo
Nada, top/left não têm efeito
Fica no fluxo, o espaço original é mantido
A sua própria posição normal
Sai do fluxo
Padding box do ancestral posicionado mais próximo
Sai do fluxo
O viewport, a menos que um ancestral tenha transform, filter ou algo parecido
Fica no fluxo
Ancestral com rolagem mais próximo, dentro do seu pai
A demo abaixo tem uma caixa laranja dentro de uma área com rolagem. Troque o valor de position, mova os deslocamentos, role e veja a partir de onde ela é medida. Em seguida vêm um guia sobre containing blocks, um checklist para o sticky que não gruda e o atalho inset.
Escolha um valor de position para a caixa laranja.
Defina top e left, e ligue ou desligue o pai posicionado para ver qual caixa o absolute usa.
Role dentro da demo para comparar fixed e sticky.
Copie o CSS que corresponde ao que você vê.
Coloque position: relative em um card, e os filhos com absolute passam a usar esse card como moldura. Esse único padrão cobre a maioria dos layouts de selos e sobreposições.
Prefira inset: 0 a escrever top, right, bottom e left separadamente.
Um elemento fixed dentro de qualquer coisa com transform, filter, perspective ou contain: paint deixa de ficar fixo na tela. Mova-o para o fim do body ou renderize-o em um portal.
Elementos posicionados são pintados acima dos estáticos por padrão. Recorra ao z-index só quando dois elementos posicionados se sobrepõem.
Perguntas frequentes
Qual é a diferença entre absolute e relative?
relative desloca um elemento visualmente, mas deixa o seu espaço original no layout, então nada ao redor se move. absolute tira o elemento do layout por completo, os vizinhos fecham o espaço, e top ou left são medidos a partir do ancestral posicionado mais próximo, e não de onde ele estaria.
Por que position: sticky não funciona?
As causas comuns são um valor de top ausente, um ancestral com overflow hidden ou auto, ou um pai que não é mais alto que o elemento sticky. Siga o checklist desta página em ordem; os dois primeiros itens resolvem a maioria dos casos.
Em relação a quê o absolute é posicionado?
Ao seu containing block: a padding box do ancestral mais próximo cujo position seja qualquer coisa diferente de static. Ancestrais com transform, filter ou certos valores de contain também contam. Se nenhum existir, é o containing block inicial, que tem o tamanho do viewport.
Por que meu cabeçalho fixed se move com a página?
Algum ancestral tem transform, perspective, filter, backdrop-filter, will-change: transform ou contain: paint. Qualquer um deles transforma esse ancestral no containing block dos descendentes fixed, então o cabeçalho fica fixo nele em vez de na tela.
O que é inset no CSS?
Um atalho para top, right, bottom e left, seguindo o mesmo padrão de um a quatro valores do margin. inset: 0 estica um elemento posicionado por todo o seu containing block. inset-inline e inset-block definem os pares de cada eixo.
O containing block, em palavras simples
Todo deslocamento precisa de um retângulo de referência. Para elementos static e relative, é a content box do pai. Para absolute, é a padding box do ancestral posicionado mais próximo, então o padding do card não empurra um filho absolute para dentro.
Para fixed, normalmente é o viewport. Isso muda quando um ancestral recebe transform, perspective, filter, backdrop-filter, contain: paint ou um valor de will-change correspondente: o ancestral vira a referência e o elemento rola junto com ele. A demo desta página usa exatamente isso para que a caixa fixed fique dentro da moldura da demo.
Centralizando com posicionamento absolute
Com um tamanho conhecido, inset: 0 mais margin: auto coloca a caixa bem no centro e mantém as bordas nítidas nos pixels. Com um tamanho desconhecido, top: 50% e left: 50% seguidos de translate(-50%, -50%) funcionam para qualquer conteúdo.
Os dois tiram a caixa do fluxo, então o pai não cresce em volta dela. Se o pai precisar se ajustar ao conteúdo, use a centralização com grid ou flex.
Cada valor em detalhe
Valores de position
Valor
Fluxo
O que os deslocamentos fazem
Uso típico
Fica no fluxo
São ignorados
O padrão. Tudo começa aqui.
Fica no fluxo, o espaço original é mantido
Deslocam o elemento de onde ele estaria
Pequenos ajustes, e como âncora para filhos absolute.
Sai do fluxo
Posicionam o elemento dentro do containing block
Selos, sobreposições, menus suspensos, tooltips.
Sai do fluxo
Posicionam o elemento na tela
Barras de cookies, botões flutuantes, modais em tela cheia.
Fica no fluxo
Limite a partir do qual ele gruda
Cabeçalhos de tabela, títulos de seção, menus laterais.
O que cria um containing block para absolute e fixed
Ancestrais que capturam descendentes posicionados (segundo o MDN)
O ancestral tem
Os filhos absolute o usam?
Os filhos fixed o usam?
position: relative, absolute, fixed ou sticky
Sim
Não
transform, perspective, rotate, scale ou translate diferente de none
Sim
Sim
filter ou backdrop-filter diferente de none
Sim
Sim
contain: layout, paint, strict ou content
Sim
Sim
will-change citando uma dessas propriedades, como transform ou filter
Sim
Sim
content-visibility: auto
Sim
Sim
Padrões que você vai usar
Selo no canto de um card
O card é o ancestral posicionado. Deslocamentos negativos empurram o selo até a metade para fora do canto.
Cabeçalho de tabela sticky
O wrapper rola, então o th com top: 0 gruda nele. O fundo impede que as linhas apareçam por trás.
Atalho inset
Mesmo padrão do margin: um valor para todos os lados, dois para vertical e horizontal, quatro em sentido horário a partir do topo.
Você definiu um limite: top, bottom, left ou right. Sem ele, o sticky se comporta como relative.
Nenhum ancestral entre o elemento e o contêiner de rolagem tem overflow: hidden, auto ou scroll. Qualquer um deles vira o contêiner de rolagem, muitas vezes um que nunca rola. overflow: clip não cria um contêiner de rolagem.
O pai é mais alto que o elemento sticky. Ele só gruda enquanto o pai está na tela e depois sai junto com ele.
Em uma linha flex ou grid, o item não está esticado até a altura total. Adicione align-self: start para ele ter espaço para se mover.
O elemento sticky fica acima do conteúdo que rola por baixo dele. Dê a ele um fundo e um z-index se o conteúdo aparecer por trás.
A rolagem acontece mesmo no ancestral que você imagina. Confira no DevTools qual elemento tem a barra de rolagem.
Playground de position
valor de position
O pai tem position: relative
Os deslocamentos são ignorados. A caixa fica no fluxo normal entre os parágrafos.
A caixa é desenhada deslocada, mas o espaço onde ela estaria é mantido. Os vizinhos não se movem.
Medida a partir do pai tracejado, que tem position: relative.
Não há pai posicionado, então ela é medida a partir da área de rolagem da demo, o próximo ancestral posicionado acima.
Presa à moldura da demo enquanto você rola. A moldura tem um transform, o que a torna o containing block em vez da janela do navegador.
Rola com o texto até ficar a top pixels do topo do contêiner de rolagem e então fica parada até o pai sair da tela.
Área de demo com rolagem
Role dentro desta moldura. O texto é de preenchimento, só para haver algo para rolar.
Pai
Primeiro parágrafo antes da caixa.
Parágrafo depois da caixa. Veja se ele sobe quando a caixa sai do fluxo.
Linha {n} de conteúdo extra para rolar.
Conteúdo depois do pai, linha {n}.
Copiar CSS
Por que o fixed fica na moldura: a moldura tem transform: translateZ(0). Qualquer transform transforma um elemento no containing block dos descendentes fixed. Em uma página real sem um ancestral assim, o fixed se prende à janela do navegador.
Sticky não funciona: checklist
Cabeçalho sticky escondido atrás de outro conteúdo? Veja