z-index e contextos de empilhamento no CSS, desmontados em 3D
Guia de z-index e contextos de empilhamento no CSS
z-index no CSS não funciona? Contextos de empilhamento em 3D | We.Inc
Por que o z-index é ignorado, todas as propriedades que criam um contexto de empilhamento, uma visão 3D explodida das camadas, cabeçalhos fixos e dropdowns, uma escala de z-index e um checklist de depuração.
O z-index ordena elementos sobrepostos, mas só dentro do mesmo contexto de empilhamento. Um filho com z-index: 9999 não consegue ficar acima de um elemento fora do seu pai se esse pai formar um contexto com z-index menor. Os contextos surgem de position junto com z-index, opacity abaixo de 1, transform, filter, isolation: isolate e várias outras propriedades.
Por que o z-index parece ser ignorado
Sintoma
Causa provável
O z-index não tem efeito
O elemento é position: static e não é filho de flex ou grid
Um z-index enorme continua atrás
Um ancestral forma um contexto de empilhamento em uma camada mais baixa
Dropdown escondido sob a seção seguinte
O pai tem transform, opacity ou filter
Menu cortado na borda
overflow: hidden em um ancestral, nada a ver com z-index
A visão 3D abaixo separa uma pequena página nas suas camadas de empilhamento, para você ver quais caixas estão presas dentro de qual contexto. Mude os valores de z-index e ative no pai a propriedade que cria um contexto. Depois disso vêm todos os gatilhos segundo o MDN, cabeçalhos fixos com dropdowns, uma escala de tokens e uma rotina de depuração passo a passo.
Defina os valores de z-index do cabeçalho, do card e do dropdown dentro do card.
Ative um gatilho de contexto de empilhamento no card e veja o dropdown ficar preso.
Ligue a visão 3D para ver as camadas separadas e agrupadas por contexto.
Use isolation: isolate ou tire o dropdown do contexto para resolver.
Antes de aumentar um número, encontre o contexto de empilhamento. Aumentar o z-index dentro de um contexto que prende o elemento nunca ajuda.
Guarde os valores de z-index em tokens nomeados com intervalos entre eles, para que novas camadas se encaixem sem renumerar tudo.
Use isolation: isolate nos componentes para conter os valores internos de z-index, assim eles não brigam com o resto da página.
Para modais e popovers, o elemento nativo dialog e o atributo popover usam a top layer, que fica acima de qualquer z-index.
Perguntas frequentes
Por que o z-index não funciona?
Ou o elemento não está posicionado (o z-index precisa de um position diferente de static, ou de um pai flex ou grid), ou ele está preso em um contexto de empilhamento. A posição do pai no seu próprio contexto decide o resultado, e os filhos não conseguem escapar dela, seja qual for o número que tenham.
O que cria um contexto de empilhamento?
O elemento raiz, elementos posicionados com z-index, elementos fixed e sticky, filhos de flex e grid com z-index, opacity abaixo de 1, transforms, filters, clip-path, máscaras, mix-blend-mode, perspective, isolation: isolate, alguns valores de contain e will-change, contêineres de tamanho e elementos da top layer.
O que isolation: isolate faz?
Cria um novo contexto de empilhamento e nada mais, sem nenhuma mudança visual. Coloque-o na raiz de um componente para que filhos com z-index negativo fiquem atrás do fundo do próprio componente em vez de caírem atrás da página, e para que as suas camadas internas nunca se misturem com as de fora.
Como mantenho um dropdown acima da seção seguinte?
Dê ao cabeçalho ou ao contêiner que guarda o dropdown um z-index maior que o das seções seguintes, com os dois posicionados. Se o contêiner tiver transform ou opacity, lembre que ele já é um contexto próprio, então o z-index precisa ir nesse contêiner, não no dropdown.
Um z-index negativo é seguro?
É válido, mas o elemento vai para trás do fundo do seu contexto de empilhamento. Sem um contexto no pai, isso pode significar ficar atrás do fundo da página, invisível. Adicione isolation: isolate no pai para mantê-lo dentro.
Como funciona a ordem de pintura
Dentro de um contexto de empilhamento, o navegador pinta em uma ordem fixa: o fundo do próprio contexto, depois os filhos com z-index negativo, depois o conteúdo de bloco normal, floats, conteúdo inline, elementos posicionados com z-index auto ou 0 na ordem do código e, por fim, os z-index positivos, do menor para o maior.
Um contexto filho é pintado como uma unidade única na posição do seu pai nessa lista. Tudo o que está dentro é ordenado só em relação aos seus irmãos. Esse é todo o motivo de um 9999 dentro de um card com z-index: 1 perder para um vizinho com z-index: 2.
Uma rotina de depuração
Primeiro confirme que é um problema de empilhamento: se o elemento é cortado em uma borda reta, procure overflow em um ancestral. Depois suba a partir do elemento escondido no DevTools, conferindo os estilos computados de cada ancestral em busca dos gatilhos listados nesta página.
O DevTools do Chromium tem um painel Layers e o Edge tem uma 3D View que mostram as camadas compostas visualmente. Quando encontrar o ancestral que forma o contexto, suba esse ancestral, remova o gatilho ou renderize a parte flutuante fora dele.
Tudo o que cria um contexto de empilhamento
Baseado na referência de contexto de empilhamento do MDN. Basta uma condição.
Gatilhos de contexto de empilhamento
Propriedade ou estado
Condição
Elemento raiz
html é sempre o contexto de empilhamento raiz
position: absolute ou relative
Só com um z-index diferente de auto
position: fixed ou sticky
Sempre, não precisa de z-index
Filho de flex ou grid
Com um z-index diferente de auto, mesmo que position seja static
container-type: size ou inline-size
Qualquer elemento que seja um contêiner de consulta de tamanho
opacity abaixo de 1
Incluindo opacity: 0.99
Qualquer valor diferente de normal
transform, scale, rotate, translate
Qualquer valor diferente de none
filter ou backdrop-filter
Qualquer valor diferente de none
Qualquer valor diferente de none
Qualquer valor diferente de none
mask, mask-image, mask-border
Qualquer valor diferente de none
isolation: isolate
Feito exatamente para isso, sem efeitos visuais colaterais
Nomear qualquer propriedade que criaria um contexto de empilhamento quando definida
layout, paint ou um atalho que os inclua (strict, content)
Top layer
Dialog modal aberto, popover, elemento em tela cheia e o seu ::backdrop
A armadilha e as soluções
z-index 9999 que mesmo assim perde
O card azul é um contexto com z-index 1. A tooltip dele tem 9999, mas só é comparada com o que está dentro do card, então a caixa laranja com z-index 2 a cobre.
isolation: isolate mantém uma camada negativa dentro
Sem isolate, a decoração com z-index: -1 cairia atrás do fundo da seção e desapareceria. Com ele, a seção é o seu próprio contexto.
Cabeçalho sticky com um dropdown
O cabeçalho é sticky, então já é um contexto. Dê a ele um z-index acima do conteúdo e o dropdown dentro dele herda essa camada. Não precisa de números enormes.
Conteúdo normal
Cards elevados no hover, cabeçalhos fixos de tabela
Menus, listas de autocompletar
Cabeçalho fixo do site
Fundo escurecido de gaveta
Modais personalizados (o dialog nativo usa a top layer)
Notificações que precisam ficar acima de tudo
Laboratório de empilhamento com visão 3D explodida
z-index do cabeçalho
z-index do card (ou auto)
z-index do dropdown
z-index do banner
Gatilho de contexto no card
Propriedade extra no card
Visão 3D explodida (gira as camadas e as separa)
Camadas separadas, mais alto significa pintado depois
Visão plana, CSS real
Cabeçalho z {z}
Card z {z}
Dropdown z {z}
Banner z {z}
(dentro do card)
acima do banner
abaixo do banner
O card forma um contexto de empilhamento ({why}). O {d} do dropdown só vale dentro do card, então ele fica {pos} porque o card fica.
O card não é um contexto de empilhamento, então o dropdown compete diretamente: {d} contra o {b} do banner. Ele fica {pos}.
CSS desta configuração
Copiar CSS
Experimente: card z auto, dropdown 9999 e depois escolha transform. Uma única propriedade prende o dropdown.