Who's not Afraid of z-index-cover.png
Daniel Carvalho

Daniel Carvalho

15 Dez 2022 6 min de leitura

Quem não tem medo do z-index?

Antes de descobrir, graças ao curso CSS for JS devas, que o z-index tem uma lógica por trás, eu sempre caía no z-index hell, tentando colocar um elemento na frente do outro. Isso me encaminhou para medidas desesperadas como o z-index: 9999999999999, e é por isso que nesse post vou te mostrar boas e más práticas com o z-index pra que você consiga ir pro z-index heaven :)

O que é

O z-index é a propriedade CSS que usamos para alterar a ordem padrão das camadas do HTML. O padrão do navegador é renderizar o próximo elemento na frente do anterior. Desse modo, a div com a classe "box__1" ficará na última camada da pilha enquanto a div com a classe "box__3" ficará na primeira camada da pilha.

Div stack following the natural DOM order

<div class="box box__1">1</div>

<div class="box box__2">2</div>

<div class="box box__3">3</div>

Imagine que o HTML é uma pilha de camadas e o z-index é usado para definir uma nova ordem do elemento nessa pilha. Dessa forma, quanto maior o z-index de um elemento, mais acima é sua posição na pilha, ou seja, mais a frente dos outros elementos ele estará.

<style>
    .box{ position: relative }

    .box__1 { z-index: 1 }

    .box__2 { z-index: 1000 }

    .box__3 { z-index: 2 }
</style>

<div class="box box__1" >1</div>
<div class="box box__2">2</div>
<div class="box box__3">3</div>

O código acima resultará em algo como a imagem abaixo, pois a div com classe "box__2" tem o maior z-index.

Div stack following the z-index order


Em que contexto é usado

No z-index hell, você encontrará uma situação onde nem todos os elementos respeitam a posição que você definiu, como no codepen abaixo.

Em uma situação como essa normalmente entramos em uma batalha com o z-index dos elementos passando valores que vão de 100 a algum valor gigante aleatório que você só colocou para tentar resolver o conflito na ordem dos elementos. Para resolver, é preciso entender que:

  1. O z-index é aplicado em contextos, então se você não define um contexto, ele vai usar o contexto global do DOM;
  2. Por padrão, os elementos HTML têm a propriedade position definida como position: static;
  3. Para aplicar o z-index, é obrigatório mudar o posicionamento do elemento para uma das opções position: relative | absolute | sticky | fixed. Além disso, a propriedade z-index funciona sem precisar mudar o posicionamento padrão do elemento nos layouts grid e flex;
  4. Se o valor do z-index não for passado, o elemento vai respeitar a ordem padrão do DOM;
  5. O valor máximo aceito na propriedade z-index é o 2147483648, ou seja o maior número inteiro que pode ser armazenado em 32bits. Dessa forma, a regra que tiver um valor acima disso será ignorada.

Mau uso

Em uma aplicação grande, o z-index pode ser um problema ainda maior, pois pode haver vários elementos com o z-index explicitamente declarado. Nesse caso, você pode acabar afetando algum outro elemento ao tentar fazer alterações nesses elementos “z-indexados”.

Geralmente nessa situação minha abordagem era sempre tentar valores aleatórios até achar um que se encaixasse perfeitamente no contexto. Isso era uma verdadeira gambiarra dependente da sorte que me fazia chegar em situações como a abaixo.


Bom uso

Mas você não precisa passar por isso, há alternativas para evitar esses problemas! Abaixo vou mostrar diferentes abordagens que podem evitar o z-index hell.

Isolation: isolate

A propriedade isolation é suportada por todos os navegadores, exceto o IE. Por padrão, seu valor é auto, permitindo que o z-index dos filhos de um elemento se misturem com todos os outros elementos do DOM.

Quando usamos o valor isolate, passamos a isolar o z-index dos filhos desse elemento apenas em seu contexto. Com isso, você pode declarar por exemplo z-index: 1000 em um filho e esse valor vai ser considerado apenas na pilha de elementos do contexto, fazendo com que o problema acima não ocorra mais. No código abaixo eu isolo os elementos header e posts em um contexto para que eles não fiquem na frente do modal. Veja no codepen abaixo.


CSS variables

Outra abordagem amplamente utilizada é criação de variáveis para camadas de z-index. Essa abordagem é utilizada pelo Bootstrap e se baseia na criação de “break points” que guiam a prioridade do elemento nas camadas do z-index. Por exemplo, um modal precisa ficar acima de um dropdown, então a sua variável vai ter um valor maior que a do dropdown. Isso evita que o time use valores aleatórios.

/* css variables */
$zindex-flow: 100;
$zindex-modal-backdrop: 1040;
$zindex-modal: 1060;

/* css variables */
--zindex-flow: 100;
--zindex-modal-backdrop: 1040;
--zindex-modal: 1060;


Tailwind approach

O Tailwind utiliza a abordagem de aplicar classes ao elemento que precisa de um z-index explícito. Com isso, o time consegue ter uma visão clara da posição do elemento na pilha por meio de índices que vão de z-0 a z-50 por padrão, podendo ser sobrescritos usando o z-[100].

$zIndex: (
  "0": 0,
  "10": 10,
  "20": 20,
  "30": 30,
  "40": 40,
  "50": 50,
  "60": 60,
  "70": 70,
  "80": 80,
  "90": 90,
  "100": 100,
  "auto": "auto",
);

@each $index, $level in $zIndex {
  .z-#{$index} {
    `z-index`: $level;
  }
}


Portals

O Portals é uma abordagem oferecida por vários frameworks, como Angular e bibliotecas como React, para lidar com problemas de z-index. É uma abordagem mais recomendada para bibliotecas de UI que implementam dropdown, modal e outros componentes que precisam ter prioridade nas camadas do z-index. Dessa forma, provavelmente você não precisará usar esse tipo de solução em seus projetos, mas é importante saber que existe. Ela cria um div abaixo da div padrão que o conteúdo da aplicação é renderizado, atribui a regra position: relative para essa div e um z-index com valor alto, no React esse valor é 999.


Conclusão

Ficou com alguma dúvida ou conhece alguma outra abordagem que eu não falei aqui? Comenta aqui embaixo e vamos conversar! :))

Se quiser ler mais sobre o z-index, essas foram algumas das minhas referências: