⚡ Curso de CSS • Web-ZoneWare

z-index e Contexto de Empilhamento no CSS | Web Academy

Lição 24 de 50

z-index e Contexto de Empilhamento no CSS | Web Academy

Até agora, tratamos o navegador como uma superfície bidimensional composta pelo eixo horizontal X (largura) e pelo eixo vertical Y (altura). No entanto, no momento em que usamos coordenadas de posicionamento, caixas inevitavelmente colidem e se sobrepõem. É aqui que entra o Eixo Z: a terceira dimensão perpendicular à tela, apontando diretamente para os olhos do usuário. Controlar qual elemento fica na frente ou atrás não é uma questão de sorte nem de quem tem o maior número arbitrário no z-index, mas sim de entender a mecânica dos Contextos de Empilhamento (Stacking Contexts).

1. A Ordem Natural de Pintura (Antes de Usar z-index)

Antes de aplicarmos qualquer linha de z-index, o navegador já possui uma hierarquia rígida de 7 camadas para desenhar os pixels na tela. Quando dois elementos colidem sem z-index declarado, o motor gráfico segue esta sequência de trás para a frente (do mais profundo para o mais superficial):

Nível Tipo de Elemento / Conteúdo Comportamento no Eixo Z
1 (Fundo) Background e Bordas do Elemento Raiz A tela em branco do navegador (<html>).
2 Elementos Não-Posicionados em Bloco <div>, <section>, <p> no fluxo normal (ordem do HTML).
3 Elementos Flutuantes (Floats) Caixas com float: left ou float: right.
4 Elementos em Linha (Inline e Texto) Textos, <span>, <strong>, imagens no fluxo normal.
5 (Frente) Elementos Posicionados Qualquer caixa com position diferente de static (ordem de aparição no HTML).

Revelação Surpreendente: Apenas declarar position: relative em uma caixa — mesmo sem alterar coordenadas nem definir z-index — já a joga automaticamente para a frente de todos os blocos, floats e textos normais da página!

2. Como Funciona a Propriedade z-index

A propriedade z-index aceita números inteiros positivos, negativos ou zero. Quanto maior o valor, mais próximo da tela do usuário o elemento se posiciona:

CSS3 14 linhas
.camada-fundo {
  position: relative;
  z-index: 1;
}
 
.camada-frente {
  position: relative;
  z-index: 10; /* Fica visivelmente por cima da camada-fundo */
}
 
.marca-dagua-recuada {
  position: absolute;
  z-index: -1; /* Fica atrás do próprio texto do seu contêiner */
}

A Regra de Ouro do z-index: A propriedade z-index NÃO FUNCIONA em elementos com position: static comum. Para que o z-index tenha efeito, o elemento precisa:

  • Possuir posicionamento explícito: relative, absolute, fixed ou sticky; OU
  • Ser um item filho direto de um contêiner Flexbox (display: flex) ou CSS Grid (display: grid), onde o CSS moderno permite z-index mesmo sem declarar position!

3. O Mito do z-index: 999999 e os Contextos de Empilhamento

Todo desenvolvedor já viveu esse pesadelo: você precisa que um menu dropdown ou modal fique na frente de outro cartão. Você aplica z-index: 10. Não funciona. Você tenta z-index: 999. Nada. Em desespero, você escreve z-index: 99999999 !important; e o elemento continua teimosamente atrás do outro componente!

Por que isso acontece? Porque o z-index não é um valor global absoluto. Ele é relativo ao seu Contexto de Empilhamento (Stacking Context) local.

A Metáfora dos Andares do Prédio

Pense no Stacking Context como prédios de apartamentos:

  • O Prédio A tem uma altura no térreo (z-index: 1).
  • O Prédio B tem uma base elevada (z-index: 2).
  • Se você subir na cobertura do Prédio A (andar z-index: 999999), você nunca estará acima de alguém que está no saguão do Prédio B (z-index: 2), porque a base de B é superior à base de A!
HTML5 11 linhas
<!-- Exemplo da Armadilha Clássica -->
<div class="card-a" style="position: relative; z-index: 1;">
  <!-- Este tooltip NUNCA conseguirá ficar na frente do card-b! -->
  <div class="tooltip" style="position: absolute; z-index: 999999;">
    Tooltip Preso no Teto do Pai
  </div>
</div>
 
<div class="card-b" style="position: relative; z-index: 2;">
  <p>Conteúdo do Card B (Vence tudo dentro do Card A)</p>
</div>

4. Os 7 Gatilhos que Criam Novos Contextos de Empilhamento

Um novo Contexto de Empilhamento é gerado no navegador sempre que um elemento atende a qualquer uma das seguintes condições:

  1. O elemento raiz do documento (<html>).
  2. Qualquer elemento posicionado (relative ou absolute) cujo z-index seja diferente de auto (ex.: z-index: 0 já cria um novo contexto!).
  3. Qualquer elemento com position: fixed ou position: sticky.
  4. Itens flex ou grid cujo z-index seja diferente de auto.
  5. Elementos com opacidade reduzida: opacity < 1.
  6. Elementos com transformações ou filtros gráficos: transform, filter, perspective, clip-path ou mask diferentes de none.
  7. Elementos com isolation: isolate.

5. A Arma Secreta do CSS Moderno: isolation: isolate

No passado, para criar um contexto de empilhamento isolado em um componente (evitando que seus elementos internos colidissem com o restante do site), os programadores recorriam a “hacks” como position: relative; z-index: 0; ou transform: translateZ(0);.

O CSS moderno introduziu a propriedade isolation: isolate especificamente para resolver esse problema com elegância cirúrgica:

CSS3 5 linhas
.card-componente {
  /* Cria uma fronteira de empilhamento local estrita */
  /* Nada de z-index interno vazará para o resto da página! */
  isolation: isolate;
}

Com isolation: isolate, você pode usar z-index: -1 dentro do card para colocar uma imagem decorativa atrás do texto, sem o risco da imagem afundar para trás do fundo da página inteira!

6. Arquitetura Profissional: Tokens de Camadas no Design System

Para exterminar para sempre a “guerra de z-index” nos seus projetos corporativos, nunca escreva números mágicos dispersos pelo CSS. Padronize uma escala com variáveis CSS no seu :root:

CSS3 22 linhas
:root {
  /* Escala Semântica de Camadas Z-Index */
  --z-abaixo:       -1;   /* Decorações atrás do fluxo */
  --z-padrao:        1;   /* Conteúdo básico elevado */
  --z-dropdown:    100;   /* Menus suspensos e selects */
  --z-sticky:      200;   /* Barras de navegação fixas */
  --z-overlay:     500;   /* Máscaras escuras de fundo */
  --z-modal:       510;   /* Janelas modais e diálogos */
  --z-popover:     800;   /* Tooltips e balões explicativos */
  --z-toast:      1000;   /* Alertas e notificações críticas */
}
 
/* Aplicação Limpa e Autoexplicativa */
.menu-dropdown {
  position: absolute;
  z-index: var(--z-dropdown);
}
 
.janela-modal {
  position: fixed;
  z-index: var(--z-modal);
}

7. Laboratório Prático: O Fenômeno do Contexto de Empilhamento

No código abaixo, experimente observar como o Card 1 (com z-index: 1) não consegue colocar seu distintivo à frente do Card 2 (com z-index: 2), e como o uso de isolation: isolate organiza os planos de profundidade:

HTML5 82 linhas
<!DOCTYPE html>
<html lang="pt-BR">
<head>
  <meta charset="UTF-8">
  <title>Laboratório de Camadas z-index</title>
  <style>
    body {
      font-family: 'Inter', system-ui, sans-serif;
      background: #0f172a;
      color: #f8fafc;
      padding: 40px;
    }
 
    .painel-demonstracao {
      position: relative;
      width: 480px;
      height: 260px;
      background: #1e293b;
      border: 1px solid #334155;
      border-radius: 16px;
      padding: 20px;
    }
 
    /* Card 1 - Nível Base 1 */
    .card-1 {
      position: absolute;
      top: 30px;
      left: 30px;
      width: 240px;
      padding: 20px;
      background: #3b82f6;
      border-radius: 10px;
      z-index: 1; /* Cria um Stacking Context de nível 1 */
    }
 
    /* Distintivo de z-index gigante dentro do Card 1 */
    .badge-insana {
      position: absolute;
      bottom: -15px;
      right: -30px;
      background: #ef4444;
      color: #fff;
      padding: 8px 16px;
      border-radius: 9999px;
      font-weight: 800;
      font-size: 0.75rem;
      z-index: 99999; /* INÚTIL: Preso ao teto z-index: 1 do pai! */
      box-shadow: 0 4px 12px rgba(0,0,0,0.5);
    }
 
    /* Card 2 - Nível Base 2 */
    .card-2 {
      position: absolute;
      top: 80px;
      left: 140px;
      width: 240px;
      padding: 20px;
      background: #10b981;
      border-radius: 10px;
      z-index: 2; /* Vence o Card 1 E a badge de 99999! */
      box-shadow: 0 10px 25px rgba(0,0,0,0.4);
    }
  </style>
</head>
<body>
  <h2>Por que z-index: 99999 Perde para z-index: 2?</h2>
 
  <div class="painel-demonstracao">
    <div class="card-1">
      <h4 style="margin:0;">Card 1 (z-index: 1)</h4>
      <div class="badge-insana">z-index: 99999</div>
    </div>
 
    <div class="card-2">
      <h4 style="margin:0;">Card 2 (z-index: 2)</h4>
      <p style="font-size:0.85rem; margin-bottom:0;">
        Observe que eu fico por cima da badge vermelha, embora meu z-index seja apenas 2!
      </p>
    </div>
  </div>
</body>
</html>

Teste esse exemplo interativo no Playground IDE, experimente inverter os z-index dos pais ou aplicar isolation: isolate para comprovar o comportamento gráfico na prática:

⚡ Abrir no Playground IDE →

8. Resumo e Próximos Passos

  • z-index controla a posição no eixo Z (profundidade perpendicular à tela).
  • Elementos posicionados (relative, absolute, etc.) ficam naturalmente à frente do fluxo normal antes de qualquer z-index ser digitado.
  • z-index não funciona em caixas estáticas normais; exige posicionamento ou ser filho direto de Flex/Grid.
  • Valores astronômicos como z-index: 999999 falham quando o elemento pai está em um Contexto de Empilhamento inferior.
  • A propriedade moderna isolation: isolate cria uma fronteira limpa e estrita de camadas sem efeitos colaterais visuais.

Próximo Passo: Agora que você domina as coordenadas e o empilhamento em camadas, o que acontece quando o conteúdo de uma caixa é maior do que o tamanho delimitado para ela? Na Lição 25, dominaremos Overflow & Controle de Rolagem no CSS (visible, hidden, scroll, auto e clip)!

Rolar para cima