Você já definiu z-index: 99999 em um elemento do seu CSS e ele não aparece em cima dos outros elementos? Um valor tão grande deve facilmente colocar esse elemento visualmente em cima de qualquer outro, assumindo que todos os diferentes elementos estão definidos com um valor inferior ou não estão definidos. Uma página web geralmente é representada em um espaço bidimensional; no entanto, ao aplicar propriedades CSS específicas, um plano imaginário do eixo z é introduzido para transmitir profundidade. Esse plano é perpendicular à tela e a partir dele o usuário percebe a ordem dos elementos, um em cima do outro. A ideia por trás do eixo z imaginário, a percepção do usuário sobre os elementos empilhados, é que as propriedades CSS que o criam se combinam para formar o que chamamos de contexto de empilhamento. Falaremos sobre como os elementos são “empilhados” em uma página da web, o que controla a ordem de empilhamento e abordagens práticas para “desempilhar” elementos quando necessário. Sobre contextos de empilhamento Imagine sua página da web como uma mesa. Ao adicionar elementos HTML, você coloca pedaços de papel, um após o outro, sobre a mesa. O último pedaço de papel colocado é equivalente ao elemento HTML adicionado mais recentemente e fica em cima de todos os outros papéis colocados antes dele. Este é o fluxo normal do documento, mesmo para elementos aninhados. A própria mesa representa o contexto de empilhamento raiz, formado pelo elemento , que contém todas as outras pastas. Agora, propriedades CSS específicas entram em ação. Propriedades como posição (com índice z), opacidade, transformação e contenção) atuam como uma pasta. Esta pasta pega um elemento e todos os seus filhos, extrai-os da pilha principal e os agrupa em uma subpilha separada, criando o que chamamos de contexto de empilhamento. Para elementos posicionados, isso acontece quando declaramos um valor de índice z diferente de auto. Para propriedades como opacidade, transformação e filtro, o contexto de empilhamento é criado automaticamente quando valores específicos são aplicados.
Tente entender isto: uma vez que um pedaço de papel (ou seja, um elemento filho) está dentro de uma pasta (ou seja, o contexto de empilhamento do pai), ele nunca poderá sair dessa pasta ou ser colocado entre papéis em uma pasta diferente. Seu índice z agora é relevante apenas dentro de sua própria pasta.
Na ilustração abaixo, o Papel B está agora no contexto de empilhamento da Pasta B e só pode ser encomendado com outros papéis na pasta.
Imagine, se quiser, que você tem duas pastas em sua mesa:
.folder-a { índice z: 1; } .folder-b { índice z: 2; }
Vamos atualizar um pouco a marcação. Dentro da pasta A há uma página especial, índice z: 9999. Dentro da pasta B há uma página simples, índice z: 5.
.página especial {índice z: 9999; } .plain-page { índice z: 5; }
Qual página está no topo? É a página .plain na pasta B. O navegador ignora os documentos filhos e empilha as duas pastas primeiro. Ele vê a Pasta B (índice z: 2) e a coloca no topo da Pasta A (índice z: 1) porque sabemos que dois é maior que um. Enquanto isso, a página .special definida como z-index: 9999 está na parte inferior da pilha, embora seu índice z esteja definido com o valor mais alto possível. Os contextos de empilhamento também podem ser aninhados (pastas dentro de pastas), criando uma “árvore genealógica”. O mesmo princípio se aplica: uma criança nunca pode escapar da pasta dos pais. Agora que você sabe como os contextos de empilhamento se comportam como pastas que agrupam e reordenam camadas, vale a pena perguntar: por que certas propriedades — como transformação e opacidade — criam novos contextos de empilhamento? O problema é o seguinte: essas propriedades não criam contextos de empilhamento devido à sua aparência; eles fazem isso por causa de como o navegador funciona nos bastidores. Ao aplicar transformação, opacidade, filtro ou perspectiva, você está dizendo ao navegador: “Ei, este elemento pode se mover, girar ou desaparecer, então esteja pronto!”
Ao usar essas propriedades, o navegador cria um novo contexto de empilhamento para gerenciar a renderização com mais eficiência. Isso permite que o navegador lide com animações, transformações e efeitos visuais de forma independente, reduzindo a necessidade de recalcular como esses elementos interagem com o restante da página. Pense nisso como se o navegador dissesse: “Vou cuidar desta pasta separadamente para não ter que reorganizar a mesa inteira sempre que algo dentro dela mudar”. Mas háum efeito colateral. Depois que o navegador eleva um elemento para sua própria camada, ele deve “achatar” tudo dentro dele, criando um novo contexto de empilhamento. É como tirar uma pasta da mesa para manuseá-la separadamente; tudo dentro dessa pasta é agrupado e o navegador agora a trata como uma unidade única ao decidir o que fica em cima do quê. Portanto, mesmo que as propriedades de transformação e opacidade pareçam não afetar a maneira como os elementos se empilham visualmente, elas afetam, e isso é para otimização do desempenho. Várias outras propriedades CSS também podem criar contextos de empilhamento por motivos semelhantes. O MDN fornece uma lista completa se você quiser se aprofundar. Existem alguns, o que apenas ilustra como é fácil criar inadvertidamente um contexto de empilhamento sem saber. O problema do “desempilhamento” Problemas de empilhamento podem surgir por vários motivos, mas alguns são mais comuns que outros. Os componentes modais são um padrão clássico porque exigem alternar o componente para “abrir” em uma camada superior acima de todos os outros elementos e, em seguida, removê-lo da camada superior quando estiver “fechado”. Tenho bastante certeza de que todos nós já passamos por uma situação em que abrimos um modal e, por algum motivo, ele não aparece. Não é que não tenha aberto corretamente, mas está fora de vista em uma camada inferior do contexto de empilhamento. Isso deixa você se perguntando “como é que?” já que você definiu:
.sobreposição { posição: fixa; /* cria o contexto de empilhamento */ índice z: 1; /* coloca o elemento em uma camada acima de todo o resto */ inserção: 0; largura: 100%; altura: 100vh; estouro: oculto; cor de fundo: #00000080; }
Isso parece correto, mas se o elemento pai que contém o gatilho modal for um elemento filho dentro de outro elemento pai que também está definido como índice z: 1, isso tecnicamente coloca o modal em uma subcamada obscurecida pela pasta principal. Vejamos esse cenário específico e algumas outras armadilhas comuns no contexto de empilhamento. Acho que você verá não apenas como é fácil criar contextos de empilhamento inadvertidamente, mas também como gerenciá-los mal. Além disso, como você retorna a um estado gerenciado depende da situação. Cenário 1: O Modal Preso
Você pode ver imediatamente seu modal preso em uma camada de baixo nível e identificar o pai. Extensões de navegador Desenvolvedores inteligentes criaram extensões para ajudar. Ferramentas como esta extensão do Chrome “CSS Stacking Context Inspector” adicionam uma guia z-index extra ao seu DevTools para mostrar informações sobre os elementos que criam um contexto de empilhamento.
Extensões IDE Você pode até detectar problemas durante o desenvolvimento com uma extensão como esta para VS Code, que destaca possíveis problemas de contexto de empilhamento diretamente em seu editor.
Desempilhando e recuperando o controle Depois de identificarmos a causa raiz, a próxima etapa é lidar com ela. Existem várias abordagens que você pode adotar para resolver esse problema e vou listá-las em ordem. Você pode escolher qualquer pessoa em qualquer nível; ninguém pode reclamar ou obstruir outro. Alterar a estrutura HTML Esta é considerada a solução ideal. Para você se deparar com um problema de contexto de empilhamento, você deve ter colocado alguns elementos em posições engraçadas dentro do seu HTML. A reestruturação da página ajudará você a remodelar o DOM e eliminar o problema de contexto de empilhamento. Encontre o elemento problemático e remova-o do elemento de captura na marcação HTML. Por exemplo, podemos resolver o primeiro cenário, “The Trapped Modal”, movendo o .modal-container para fora do cabeçalho e colocando-o sozinho no elemento
.Este conteúdo tem um índice z de 2 e ainda assim não cobrirá o modal.Cabeçalho
Conteúdo Principal
Quando você clica no botão “Abrir Modal”, o modal é posicionado na frente de todo o resto como deveria estar. Veja o Cenário Pen 1: The Trapped Modal (Solution) [bifurcado] de Shoyombo Gabriel Ayomide. Ajuste oContexto de empilhamento pai em CSS E se o elemento for aquele que você não pode mover sem quebrar o layout? É melhor abordar a questão: os pais estabelecem o contexto. Encontre a propriedade (ou propriedades) CSS responsável por acionar o contexto e remova-a. Se tiver um propósito e não puder ser removido, dê ao pai um valor de índice z mais alto do que seus elementos irmãos para levantar todo o contêiner. Com um valor de índice z mais alto, o contêiner pai se move para o topo e seus filhos aparecem mais próximos do usuário. Com base no que aprendemos no cenário “The Submerged Dropdown”, não podemos mover o menu suspenso para fora da barra de navegação; não faria sentido. No entanto, podemos aumentar o valor do índice z do contêiner .navbar para ser maior que o valor do índice z do elemento .content. .navbar { histórico: #333; /* índice z: 1; */ índice z: 3; posição: relativa; }
Com essa mudança, o menu .dropdown agora aparece na frente do conteúdo sem nenhum problema.
Veja o cenário da caneta 2: o menu suspenso submerso (solução) [bifurcado] de Shoyombo Gabriel Ayomide.
Experimente portais, se estiver usando uma estrutura
Em estruturas como React ou Vue, um Portal é um recurso que permite renderizar um componente fora de sua hierarquia pai normal no DOM. Os portais são como um dispositivo de teletransporte para seus componentes. Eles permitem renderizar o HTML de um componente em qualquer lugar do documento (normalmente diretamente em document.body), mantendo-o logicamente conectado ao seu pai original para adereços, estado e eventos. Isso é perfeito para escapar de armadilhas de contexto de empilhamento, já que a saída renderizada aparece literalmente fora do contêiner pai problemático.
ReactDOM.createPortal(
Isso garante que o conteúdo do menu suspenso não fique oculto atrás do pai, mesmo que o pai tenha overflow: oculto ou um índice z inferior. No cenário “A dica de ferramenta cortada” que vimos anteriormente, usei um Portal para resgatar a dica de ferramenta do estouro: clipe oculto colocando-o no corpo do documento e posicionando-o acima do gatilho dentro do contêiner. Veja o cenário da caneta 3: a dica de ferramenta cortada (solução) [bifurcada] de Shoyombo Gabriel Ayomide. Apresentando o contexto de empilhamento sem efeitos colaterais Todas as abordagens explicadas na seção anterior visam “desempilhar” elementos de contextos de empilhamento problemáticos, mas há algumas situações em que você realmente precisará ou desejará criar um contexto de empilhamento. Criar um novo contexto de empilhamento é fácil, mas todas as abordagens apresentam um efeito colateral. Isto é, exceto pelo uso de isolamento: isolar. Quando aplicado a um elemento, o contexto de empilhamento dos filhos desse elemento é determinado em relação a cada filho e dentro desse contexto, em vez de ser influenciado por elementos fora dele. Um exemplo clássico é atribuir a esse elemento um valor negativo, como índice z: -1. Imagine que você tem um componente .card. Você deseja adicionar uma forma decorativa que fique atrás do texto do cartão, mas acima do fundo do cartão. Sem um contexto de empilhamento no cartão, z-index: -1 envia a forma para a parte inferior do contexto de empilhamento raiz (a página inteira). Isso faz com que ele desapareça atrás do fundo branco do .card: Veja o índice z negativo da caneta (problema) [bifurcado] de Shoyombo Gabriel Ayomide. Para resolver isso, declaramos isolamento: isolar no .card pai: Veja o Pen Negative z-index (solução) [bifurcado] de Shoyombo Gabriel Ayomide. Agora, o próprio elemento .card se torna um contexto de empilhamento. Quando seu elemento filho - a forma decorativa criada no pseudoelemento :before - tem índice z: -1, ele vai para a parte inferior do contexto de empilhamento do pai. Ele fica perfeitamente atrás do texto e no fundo do cartão, conforme pretendido. Conclusão Lembre-se: da próxima vez que seu índice z parecer fora de controle, será um contexto de empilhamento preso. Referências
Contexto de empilhamento (MDN) Índice Z e contextos de empilhamento (web.dev) “Como Criar um Novo Contexto de Stacking com a Propriedade Isolation em CSS”, Natalie Pina “Que diabos, índice z??”, Josh Comeau
Leitura adicional no SmashingMag
“Gerenciando CSS Z-Index em grandes projetos”, Steven Frieson “Cabeçalhos fixos e elementos de altura total: uma combinação complicada”, Philip Braunen “Gerenciando Z-Index em um aplicativo da Web baseado em componentes”, Pavel Pomerantsev “A propriedade CSS Z-Index: uma visão abrangente”, Louis Lazaris