Curso de CSS / position: relative, absolute, fixed e sticky

A propriedade position altera como uma caixa é posicionada e como ela participa do fluxo normal. relative mantém seu espaço original, absolute e fixed saem do fluxo, e sticky combina o posicionamento do fluxo normal com aderência restrita durante o scroll.

Compare os modos de posicionamento com static

valor Espaço original do fluxo normal Critérios de posição e rolagem
static manter Fluxo geral. Deslocamentos como top e left não são aplicados
relative manter Mover por um deslocamento a partir do local de posicionamento original
absolute não ocupado Geralmente o bloco contêiner do ancestral posicionado mais próximo.
fixed não ocupado Viewport normal. Algumas propriedades ancestrais podem mudar o critério
sticky manter Limites dos ancestrais de mecanismo de rolagem próximos e blocos contêineres

O fluxo normal é a disposição na qual os elementos ocupam espaço de acordo com as regras de formatação do documento. O texto que segue um elemento posicionado de forma absoluta não se move automaticamente para o lado dele. Quando um elemento sai do fluxo, o conteúdo seguinte pode ocupar seu espaço anterior. Evite sobreposição através da estrutura do layout ou com preenchimento apropriado. Compare o posicionamento com display: block, inline, inline-block e ocultação para entender essa diferença.

Os deslocamentos dependem do modo de posicionamento. Com posicionamento relativo, top: 16px desloca a caixa 16px para baixo a partir de sua posição original. Com posicionamento absoluto, top mede a partir de sua referência de bloco contêiner. Portanto, o mesmo número representa diferentes relações de posicionamento. Veja MDN: position.

Mantenha o espaço original com relative

relative não reposiciona os outros elementos. Mesmo que você mova um cartão um pouco para baixo, a posição inicial do próximo cartão é mantida. Portanto, ele pode sobrepor elementos abaixo ou mostrar espaço vazio acima. Se o objetivo é alterar o espaçamento de todo o documento, primeiro verifique se a margem, o padding e o gap estão apropriados, em vez de usar top relativo.

Outro uso de relative é criar uma referência de posicionamento absoluto para os filhos. Se você apenas escrever position: relative no elemento pai e não especificar um deslocamento, o próprio pai não se moverá e se tornará a base para o badge do filho. Especificar uma posição não significa imediatamente que todos os elementos se sobreponham ou saiam do fluxo do documento.

Encontre o bloco de referência de absolute

Elementos com posição absoluta geralmente são posicionados em relação ao seu ancestral mais próximo que não seja estático. Se você definir position: relative no cartão e position: absolute com top e right no filho, ele se torna um badge dentro do card. Se não houver um ancestral correspondente, um critério mais externo é usado, o que pode fazer o badge se mover em direção à página em vez do card. Há momentos em que você cria um bloco que também inclui propriedades como transform, então você não deve apenas encontrar a declaração de posição e finalizar.

Um pai com apenas filhos absolutos não adiciona a altura de seus filhos à altura do conteúdo no fluxo normal. Problemas em que o pai parece ter altura zero ou as bordas estão colapsadas podem ocorrer mesmo que os filhos estejam visíveis. Se o conteúdo precisar determinar naturalmente a altura do pai, é mais fácil gerenciá-la colocando os filhos no fluxo e tornando apenas os pequenos selos sobrepostos absolutos.

Compare fluxo normal e um selo absoluto

Salve o código abaixo como position-flow.html. As três seções são compostas pelo elemento frontal, alvo e elemento traseiro na mesma ordem HTML. Os 12px do selo do cartão são os deslocamentos a partir das bordas superior e direita da área de referência do cartão, e o preenchimento superior é garantido para que não sobreponha o corpo do cartão.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>position-flow.html</title>
  <style>
* { box-sizing: border-box; }
body { margin: 16px; font: 16px/1.6 sans-serif; color: #243447; }
h1 { font-size: 24px; } h2 { font-size: 20px; margin-top: 32px; }
a { color: #145f8f; } a:focus-visible { outline: 3px solid #b4470b; outline-offset: 3px; }
.flow { border: 2px dashed #789; margin-bottom: 40px; margin-right: 24px; }
 .flow > div { height: 56px; padding: 12px; background: #e8f5de; }
 .flow .target { background: #dceefa; }
 .relative .target { position: relative; top: 16px; left: 20px; }
 .absolute { position: relative; }
 .absolute .target { position: absolute; top: 16px; left: 20px; }
 .card { position: relative; padding: 64px 20px 20px; background: #dceefa; max-width: 600px; }
 .badge { position: absolute; top: 12px; right: 12px; padding: 4px 12px; background: #ffe4b5; }
  </style>
</head>
<body>
<h1>Does the original space remain?</h1>
<h2>static</h2><div class="flow static"><div>Front element</div><div class="target">Target</div><div class="after">Back element</div></div>
<h2>relative</h2><div class="flow relative"><div>Front element</div><div class="target">Target</div><div class="after">Back element</div></div>
<h2>absolute</h2><div class="flow absolute"><div>Front element</div><div class="target">Target</div><div class="after">Back element</div></div>
<h2>Badge inside the card</h2><div class="card"><span class="badge">News</span><p>The badge sits at the top right of the card. Top padding separates it from the text.</p></div>
</body>
</html>
  1. Compare a posição do elemento seguinte nas seções estática e relativa. Mesmo se o alvo relativo for movido para baixo em 16px, o espaço de colocação para o elemento posterior é mantido em relação à posição original do alvo. Confirme alterando apenas o top para 0 e depois restabeleça para 16px.
  2. Uma seção absoluta tira o alvo do fluxo e coloca o elemento seguinte imediatamente após o elemento anterior. Se você mudar a posição de .absolute .target para static, a altura do elemento pai aumentará pela altura do alvo. Após a comparação, restaure para absolute.
  3. Remova temporariamente apenas position: relative de .card do selo do cartão. Depois de confirmar que o selo não está mais ancorado no canto superior direito do cartão, restaure-o imediatamente. Outras condições não mudam.
  4. Alongue as letras no selo e verifique o espaçamento entre elas e o texto principal. absolute não empurra automaticamente o corpo, então, se o seu selo puder ter várias linhas, você deve considerar se apenas o padding fixo é suficiente. Depois da prática, retorne às letras originais.

Compare fixed e sticky durante a rolagem

fixed geralmente é ancorado à área de visualização, mantendo sua posição na tela mesmo quando o documento é rolado. Pode ser usado para pequenos elementos de operação, como o botão superior no canto inferior direito da tela. Ele não ocupa espaço no fluxo, então se você tiver uma barra fixed, certifique-se de deixar espaço suficiente para que não obscureça o final do texto do corpo e o objeto de foco.

O transform de um ancestral pode estabelecer o bloco contêiner para um descendente fixed, substituindo a referência usual à área de visualização. Se um elemento fixed se move com uma caixa específica, inspecione propriedades dos ancestrais, como transform e filter. Este exemplo exclui essas propriedades para demonstrar o posicionamento na área de visualização.

Sticky requer um valor de limite não automático, como top no eixo, para observar o efeito sticky. O título não fica fixo na tela desde o início, mas permanece em sua posição de fluxo e se fixa quando alcança o limiar superior definido por top durante a rolagem. Quando atinge o final de seu elemento pai, ele se move dentro de seus limites e não continua a flutuar acima da próxima seção.

Sticky é influenciado por seus ancestrais próximos com mecanismo de rolagem. Ancestrais com overflow: auto, scroll ou hidden podem alterar a referência, mesmo quando o ancestral com esse mecanismo não é o elemento que está efetivamente rolando. Se a área de rolagem real for diferente do ancestral esperado, ou a altura do container e do título forem semelhantes e não houver espaço para movimento, a ação de fixação pode não ser visível. Em vez de apenas remover o overflow, primeiro verifique quais elementos têm rolagem.

Observe o início fixo e os limites do elemento pai

Salve o exemplo como position-scroll.html. Uma área de introdução de pelo menos 320px de altura mantém o título fixo abaixo do topo inicial da tela. O capítulo e a seção seguinte têm altura suficiente para observar quando a fixação começa e quando o limite do elemento pai o libera.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>position-scroll.html</title>
  <style>
* { box-sizing: border-box; }
body { margin: 16px; font: 16px/1.6 sans-serif; color: #243447; }
h1 { font-size: 24px; } h2 { font-size: 20px; margin-top: 32px; }
a { color: #145f8f; } a:focus-visible { outline: 3px solid #b4470b; outline-offset: 3px; }
body { margin: 0; padding-bottom: 80px; }
 .intro { min-height: 320px; padding: 24px; background: #eef2f6; }
 .chapter { min-height: 760px; background: #e8f5de; }
 .sticky { position: sticky; top: 0; margin: 0; padding: 16px; background: #dceefa; border-bottom: 2px solid #789; }
 .chapter p { padding: 16px; }
 .tail { min-height: 900px; padding: 24px; background: #fff2df; }
 .fixed { position: fixed; right: 16px; bottom: 16px; padding: 12px; background: #fff; border: 2px solid #145f8f; }
  </style>
</head>
<body>
<div class="intro" id="top"><h1>A heading that sticks while scrolling</h1><p>The heading below starts in normal flow. It sticks when it reaches the top of the screen and remains within its parent at the end of the chapter.</p></div>
<section class="chapter"><h2 class="sticky">Chapter heading</h2><p>This content is inside the chapter. The extra height lets you observe how long its heading remains sticky.</p></section>
<section class="tail"><h2>Another section</h2><p>Check whether the previous chapter's heading stays above this section.</p></section>
<a class="fixed" href="#top">Back to top</a>
</body>
</html>
  1. Antes de rolar, certifique-se de que o título está abaixo da área introdutória. Abaixe-o lentamente para que o título fique fixo quando alcançar o topo da tela. O link superior no canto inferior direito permanece na mesma posição da tela desde o início.
  2. Role pelo capítulo e vá para outra área. O título sticky fica limitado pelo capítulo pai e sai do topo quando esse limite é alcançado; o link fixed continua na posição da janela. Clique no link para retornar à área introdutória.
  3. Se você mudar apenas o top de .sticky para auto, não haverá um limiar vertical definido neste exemplo e ele vai rolar como um fluxo normal. Após a confirmação, restaure para 0.
  4. Basta adicionar overflow: hidden ao seu .chapter para ver os resultados do sticky ao rolar a janela quando o ancestral mais próximo com mecanismo de rolagem for alterado. Após comparar, remova a declaração adicionada.

Diagnostique posicionamento inesperado

Se a ordem de empilhamento não mudar mesmo após especificar a posição, verifique o z-index e contextos de empilhamento.

  1. Primeiro, verifique se há espaço disponível. O posicionamento dos elementos ao redor varia dependendo se eles são relative/sticky ou absolute/fixed.
  2. Verifique a posição real e os valores aplicados de top, right, bottom e left nas ferramentas de desenvolvedor. Também verifique quais regras e media queries têm precedência.
  3. absolute verifica o ancestral base, e fixed verifica a propriedade do ancestral que altera o bloco de contenção. sticky verifica limite, ancestral de rolagem, altura do pai e margem de movimento.
  4. Se as coordenadas estiverem corretas mas estiverem ocultas, diferencie entre um problema de localização e uma ordem de sobreposição/truncamento de overflow. Um z-index grande não resolve todas as occlusões.