Curso de CSS / z-index e contextos de empilhamento

O z-index controla a sobreposição dentro do contexto de empilhamento relevante, em vez de atribuir a cada elemento uma profundidade global. Um filho com um z-index alto pode permanecer atrás de um elemento em um contexto de ancestral mais elevado, e o z-index não pode desfazer o recorte por overflow.

Separe o posicionamento da ordem de empilhamento

Para comparar a ordem de sobreposição, os dois elementos devem realmente ocupar a mesma área da tela. Se eles estiverem completamente à esquerda e à direita, ou para cima e para baixo, alterar o z-index não fará diferença. Primeiro, verifique a posição retangular do elemento nas ferramentas de desenvolvedor e determine se existem áreas de sobreposição. Para os padrões de posicionamento de elementos sobrepostos, verifique os padrões de espaço e coordenadas do CSS position: relative, absolute, fixed e sticky.

A posição determina o padrão de coordenadas e a participação no fluxo, e o z-index determina o que fica na frente e atrás quando há sobreposição. Alterar as coordenadas com top e alterar a ordem com z-index são tarefas diferentes. O exemplo abaixo fixa as posições do badge e do card e então altera apenas o z-index do elemento pai, para que você possa comparar as duas funções sem confundi-las.

O z-index pode ser aplicado a elementos posicionados, como relative e absolute, e pode ser usado para itens Flex e itens Grid mesmo que o position seja static. Se você apenas atribuir números a blocos gerais de fluxo comum e esperar efeitos, as condições de aplicação podem não ser atendidas. Você pode verificar o significado do alvo e do valor na descrição do z-index do MDN.

Compare contextos de empilhamento como grupos

Um contexto de empilhamento agrupa seus descendentes para comparações externas de empilhamento. Se o pai à esquerda tiver z-index: 1 e o cartão à direita tiver z-index: 2, um selo filho com z-index: 9999 dentro do contexto esquerdo não compete diretamente com o cartão à direita. O grupo pai permanece abaixo dele.

Left parent context: z-index 1
└ Child badge: z-index 9999
Right card context: z-index 2

Outside, compare parent 1 and card 2.

Elevar o pai esquerdo para z-index: 3 coloca todo o seu contexto acima do cartão à direita em 2. O selo filho mantém seu próprio valor 9999, mas se torna visível na sobreposição. Os números de ancestrais e descendentes não são somados para produzir um valor global como 10000. Veja MDN: Contexto de empilhamento.

Identifique declarações que criam contextos

Condições representativas Criar um novo contexto O que verificar
relative ou absolute com z-index diferente de auto Sim 0 também é um número e é diferente de auto.
fixed ou sticky Sim Cria contexto mesmo se z-index for auto
Item Flex ou Grid + z-index não auto Sim Possível sem posição
opacity menor que 1 Sim Afeta relações de grupo bem como visibilidade
transform não é none Sim Mesmo que a quantidade de movimento seja 0, é diferente de none
isolation: isolate Sim Como criar intencionalmente um contexto separado

A tabela acima é uma lista de condições frequentemente encontradas e não é uma lista de todas as condições de criação. Você deve distinguir entre casos em que apenas relative é especificado e z-index é auto, e casos em que z-index: 0 é especificado para relative. Se a sobreposição mudou, verifique não apenas o número, mas também a opacidade ou transform recém-adicionados ao ancestral.

Dentro do mesmo contexto, você pode comparar a frente e o verso usando o número z-index do elemento que atende às condições de aplicação. No entanto, porque a ordem geral de desenho do CSS tem múltiplos níveis, incluindo níveis negativos, fluxo normal e elementos posicionados, não trate o auto de todos os elementos como igual ao número 0 nem calcule a ordem geral da página apenas com base nos números. A prática de aprendizado restringe as condições a números positivos e ao contexto explícito do pai.

Compare os valores de z-index do pai e do filho

Salve o código abaixo como stacking-context.html e abra-o. O selo é posicionado a 80-144px do topo, e o cartão à direita é colocado na área de 110-230px, com uma sobreposição vertical de 34px. As posições esquerda e direita usam uma proporção em relação à largura do elemento pai para manter a sobreposição no celular. Pais e itens são calculados como border-box e configurados para evitar transbordamento desnecessário fora do contêiner.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>stacking-context.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; }
.scene { position: relative; width: min(100%, 520px); height: 300px; background: #f1f4f7; }
 .left { position: absolute; z-index: 1; left: 0; top: 20px; width: 60%; height: 180px;
 padding: 16px; background: #ffe3b5; }
 .badge { position: absolute; z-index: 9999; left: 70%; top: 60px; width: 50%; height: 64px;
 padding: 8px; background: #f5a7cc; }
 .right { position: absolute; z-index: 2; left: 50%; top: 110px; width: 45%; height: 120px;
 padding: 12px; background: #9cd4f2; }
 .raised .left { z-index: 3; }
  </style>
</head>
<body>
<h1>Child and parent z-index values</h1><h2>Parent: 1; right card: 2</h2><div class="scene original"><div class="left">Left parent<div class="badge">Child badge<br>9999</div></div><div class="right">Right card<br>z-index: 2</div></div><h2>Parent: 3; right card: 2</h2><div class="scene raised"><div class="left">Left parent<div class="badge">Child badge<br>9999</div></div><div class="right">Right card<br>z-index: 2</div></div>
</body>
</html>

Na primeira seção, a parte sobreposta do selo rosa fica coberta pelo cartão azul, e na segunda seção, o selo rosa está visível sobre o cartão azul. A única diferença entre as duas zonas é 1 e 3 do pai esquerdo. O diagrama explicativo a seguir ilustra os dois estados com as mesmas coordenadas relativas; não é uma captura de tela do navegador.

With the parent at z-index 1, the child at 9999 is behind the neighboring card at 2. By raising the parent to 3, the child appears in front, without changing the coordinates.

  1. Aumente apenas o valor de z-index de .badge na primeira seção para 99999. O relacionamento entre o Pai 1 e o Cartão 2 é mantido, então a parte sobreposta continua sendo coberta pelo cartão. Restaura o número para 9999.
  2. Adicione a regra .original .left { z-index: 3; }. O badge vai subir no cartão sem alterar as coordenadas. Após a confirmação, remova a regra adicionada.
  3. Na primeira seção original, altere apenas o z-index de .left para auto. Neste exemplo, sem outras propriedades de criação, o pai esquerdo não cria um contexto separado, então o contexto do badge é comparado ao cartão externo. Certifique-se de que o badge esteja visível à frente e restaure para 1.
  4. Ajuste a largura da tela para garantir que o selo e o cartão ainda se sobreponham. Como mudanças numéricas não são visíveis quando as coordenadas estão separadas, as comparações devem ser feitas mantendo a área de sobreposição.

Distinga recorte por overflow e ordem de empilhamento

Se o ancestral trunca o conteúdo com overflow: hidden, as partes fora de seus limites não podem se tornar visíveis apenas com um z-index alto. Se ele estiver à frente na ordem, mas não visível, você precisa determinar se ele está coberto por outro elemento ou cortado no limite de um ancestral. Salve o código abaixo como stacking-clip.html e execute-o. Mesmo que você aumente o z-index, se ele estiver cortado no limite do pai, verifique as condições de corte para CSS Overflow, Quebra de Texto Longo e Reticências.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>stacking-clip.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; }
.frame { position: relative; width: min(100%, 260px); height: 100px; overflow: hidden;
 border: 2px solid #789; background: #e8f5de; }
 .popup { position: absolute; z-index: 9999; left: 80%; top: 24px; width: 90px; height: 60px;
 padding: 8px; background: #f5a7cc; }
  </style>
</head>
<body>
<h1>A box that stays clipped at a higher z-index</h1><div class="frame">Parent boundary<div class="popup">Badge<br>9999</div></div><p>The right side of the badge extends beyond its parent's boundary.</p>
</body>
</html>
  1. Certifique-se de que o lado direito do badge esteja cortado na borda do elemento pai. Mesmo que você mude o z-index para 99999, a parte truncada não aparecerá. Restaure o número para 9999.
  2. Altere apenas o overflow de .frame para visible. Outras coordenadas e números permanecem os mesmos, mas a área fora do limite fica visível. Após a comparação, volte para hidden.

Em telas reais, remover o overflow pode afetar outros propósitos, como rolagem e cantos arredondados. Primeiro, determine se a truncagem é intencional e, se o popup deve ficar fora dos limites, mova a estrutura para fora do ancestral que faz a truncagem ou considere um método de exibição separado, conforme apropriado. Não altere o overflow de todos os pais de uma vez apenas porque esconde o menu.

Siga uma sequência de diagnóstico

  1. Verifique se o elemento realmente existe e não está oculto devido a display·visibility·opacity.
  2. Verifique as posições retangulares dos dois elementos para ver se há uma área de sobreposição real.
  3. Percorra o elemento-alvo e seus ancestrais para encontrar declarações que criam um contexto de empilhamento. Determine qual pai comum os contextos concorrentes estão sendo comparados.
  4. Decida se o valor a alterar pertence ao contexto do filho ou ao do pai. Verifique também os elementos irmãos afetados e ajuste os valores apenas dentro do intervalo necessário.
  5. Se você não o vir mesmo após alterar a ordem, verifique truncamentos como overflow·clip e outros padrões de coordenadas. Após concluir a comparação, os valores temporariamente modificados são restaurados para seus valores originais.

O z-index de um elemento comum não deve ser visto como um meio de superar uma camada de exibição separada, como um diálogo na camada superior, apenas aumentando o número. Ao solucionar problemas de cartões e badges padrão, é importante primeiro entender o contexto real do elemento pai e o truncamento. Em vez de apenas continuar aumentando os números, você pode configurar a ordem desejada mesmo com valores pequenos, verificando quais grupos são comparados.