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 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
.
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:
- O
z-index
é aplicado em contextos, então se você não define um contexto, ele vai usar o contexto global do DOM; - Por padrão, os elementos HTML têm a propriedade
position
definida comoposition: static
; - Para aplicar o
z-index
, é obrigatório mudar o posicionamento do elemento para uma das opçõesposition: relative | absolute | sticky | fixed
. Além disso, a propriedadez-index
funciona sem precisar mudar o posicionamento padrão do elemento nos layoutsgrid
eflex
; - Se o valor do
z-index
não for passado, o elemento vai respeitar a ordem padrão do DOM; - 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-index
ados”.
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! :))