Mudanças de empilhamento chegando à posição:elementos fixos

Tom Wiltzius
Tom Wiltzius

No Chrome 22, o comportamento de layout dos elementos position:fixed é um pouco diferente das versões anteriores. Todos os elementos position:fixed agora formam novos contextos de empilhamento. Isso vai mudar a ordem de empilhamento de algumas páginas, o que pode quebrar os layouts delas. O novo comportamento corresponde ao comportamento dos navegadores WebKit em dispositivos móveis (Safari para iOS e Chrome para Android).

O que é o empilhamento?

Todo mundo conhece e adora o z-index para determinar a ordem de profundidade dos elementos em uma página. No entanto, nem todos os Z-indexes são criados iguais: o z-index de um elemento determina apenas a ordem em relação a outros elementos no mesmo contexto de empilhamento. A maioria dos elementos em uma página está em um único contexto de empilhamento raiz, mas elementos posicionados de forma absoluta ou relativa com valores z-index não automáticos formam seus próprios contextos de empilhamento. Ou seja, todos os elementos filhos serão ordenados em z no elemento pai e não serão intercalados com conteúdo de fora dele. A partir do Chrome 22, os elementos position:fixed também vão criar os próprios contextos de empilhamento.

Para uma visão geral dos contextos de empilhamento, este artigo do MDN é uma ótima leitura.

Compare position:fixed com o novo atributo position:sticky: para referência, position:sticky sempre cria um novo contexto de empilhamento.

Motivação

Os navegadores para dispositivos móveis (Safari para dispositivos móveis, navegador Android, navegadores baseados em Qt) colocam elementos position:fixed nos próprios contextos de empilhamento e têm isso há algum tempo (desde o iOS5, Android Gingerbread etc.), porque isso permite otimizações de rolagem, tornando as páginas da Web muito mais responsivas ao toque. A mudança foi feita no computador por três motivos:

  1. Ter um comportamento de renderização diferente em navegadores "mobile" e "desktop" é um obstáculo para os autores da Web. O CSS precisa funcionar da mesma forma em todos os lugares, sempre que possível.
  2. Com tablets, não está claro qual dos algoritmos de criação de contexto de empilhamento "mobile" ou "desktop" é mais adequado.
  3. As otimizações de desempenho de rolagem do dispositivo móvel para o computador são boas para usuários e autores.

Detalhes da mudança

Confira um exemplo que mostra os diferentes comportamentos de layout: https://codepen.io/paulirish/pen/CgAof

Com a mudança, as duas versões serão renderizadas como a versão à direita.

Neste exemplo, a caixa verde tem um z-index: 1, a caixa rosa tem um z-index: 3 e a caixa laranja tem um z-index: 2. A caixa azul é um ancestral da caixa laranja e tem position:fixed.

Se a caixa azul tiver seu próprio contexto de empilhamento, o z-index da caixa laranja será calculado em relação ao contexto de empilhamento da caixa azul. Como a caixa azul tem um z-index de auto, a ela um nível de empilhamento de zero no contexto de empilhamento raiz, isso significa que a caixa laranja fica atrás das caixas verde e rosa, que têm índices Z de 1 e 3 (respectivamente) no contexto raiz.

Se a caixa azul não receber o próprio contexto de empilhamento, o z-index da caixa laranja será calculado em relação ao contexto de empilhamento raiz (junto com as caixas verde e rosa). Portanto, a caixa laranja acaba sendo intercalada com as caixas rosa e verde.

Para mais detalhes sobre os critérios para a criação de contexto de empilhamento (e como os contextos de empilhamento se comportam em geral), consulte este artigo do MDN. No exemplo, a versão do lado direito sempre dava à caixa azul o próprio contexto de empilhamento porque a opacidade dela é menor que 1. A mudança de comportamento adiciona outro critério para criar um contexto de empilhamento separado, ou seja, um elemento position:fixed.

Testes e o futuro

Para testar se a página vai mudar, acesse about:flags do Chrome e ative/desative a opção "Os elementos de posição fixa criam contextos de empilhamento". Se o layout se comportar da mesma forma nos dois casos, está tudo certo. Caso contrário, verifique se a flag ativada parece aceitável para você, já que esse será o padrão no Chrome 22.

Essa mudança remove uma capacidade: a capacidade de intercalar conteúdo em um subárvore position:fixed com conteúdo não rolável de fora. É improvável que os desenvolvedores da Web estejam fazendo isso de propósito, e o mesmo efeito pode ser criado ao fornecer vários elementos position:fixed às diferentes partes do DOM. Por exemplo, considere estes dois exemplos:

https://codepen.io/wiltzius/pen/gcjCk

Esta página tenta pegar duas divs filhas (overlayA e overlayB) de um elemento position:fixed e colocar uma acima de uma div de conteúdo separada e outra abaixo dessa mesma div de conteúdo separada. Agora é impossível fazer isso porque o elemento position:fixed é o próprio contexto de empilhamento, e ele (junto com todos os filhos) será totalmente acima ou totalmente abaixo da div de conteúdo. Observe que este exemplo funciona no Chrome 21 e versões anteriores, mas não no Chrome 22.

Para corrigir isso, as duas sobreposições podem ser divididas em elementos position:fixed. Cada um é o próprio contexto de empilhamento, e um deles pode ficar acima do div de conteúdo e outro abaixo. Confira o exemplo corrigido, que funciona no Chrome 21 e 22:

https://codepen.io/wiltzius/pen/vhFzG

O crédito pela origem deste exemplo vai para a inimitável hixie.

O Chrome é o primeiro navegador para computador que faz com que os elementos position:fixed criem seus próprios contextos de empilhamento. O padrão relevante é a especificação do índice z do CSS (consulte, por exemplo, https://www.w3.org/TR/CSS21/zindex.html). Ainda não há consenso sobre o que fazer com a diferença entre os navegadores para dispositivos móveis e computadores. No entanto, devido à confusão de ter dois comportamentos diferentes em dispositivos móveis e computadores, o Chrome optou por mudar para esse comportamento único em ambas as plataformas por enquanto.

Atualizado em 1º de outubro de 2012:a versão original deste artigo sugeria que a especificação CSS z-index já havia sido alterada para refletir o novo comportamento de position: fixed elements. Isso não é preciso. O assunto foi discutido na lista de estilo www, mas nenhuma mudança foi feita na especificação até o momento.