Ajudando os navegadores a otimizar com a propriedade CSS Contein

Publicados: 2022-03-10
Resumo rápido ↬ A propriedade CSS contain uma maneira de explicar seu layout para o navegador, para que otimizações de desempenho possam ser feitas. No entanto, ele vem com alguns efeitos colaterais em termos de layout.

Neste artigo, apresentarei uma especificação CSS que acabou de se tornar uma recomendação do W3C. A CSS Containment Specification define uma única propriedade, contain , e pode ajudá-lo a explicar ao navegador quais partes do seu layout são independentes e não precisarão ser recalculadas se alguma outra parte do layout for alterada.

Embora essa propriedade exista por motivos de otimização de desempenho, ela também pode afetar o layout de sua página. Portanto, neste artigo, explicarei os diferentes tipos de contenção dos quais você pode se beneficiar, mas também as coisas que você precisa observar ao aplicar a contain a elementos em seu site.

O problema do recálculo do layout

Se você estiver criando páginas da Web diretas que não adicionam ou alteram elementos dinamicamente após serem carregados usando JavaScript, não precisa se preocupar com o problema que o CSS Containment resolve. O navegador só precisa calcular seu layout uma vez, à medida que a página é carregada.

Onde a contenção se torna útil é quando você deseja adicionar elementos à sua página sem que o usuário precise recarregá-la. No meu exemplo, criei uma grande lista de eventos. Se você clicar no botão, o primeiro evento é modificado, um elemento flutuante é adicionado e o texto é alterado:

Uma lista de itens com um botão para alterar parte do conteúdo do primeiro item
(Veja o exemplo inicial no CodePen)

Quando o conteúdo da nossa caixa é alterado, o navegador deve considerar que algum dos elementos pode ter sido alterado. Os navegadores em geral são muito bons em lidar com isso, pois é uma coisa comum de acontecer. Dito isto, como desenvolvedor, você saberá se cada um dos componentes é independente, e que uma mudança em um não afeta os outros, então seria bom se você pudesse informar o navegador através do seu CSS. Isso é o que a contenção e a propriedade CSS contain fornecem a você.

Mais depois do salto! Continue lendo abaixo ↓

Como a contenção ajuda?

Um documento HTML é uma estrutura em árvore que você pode ver ao inspecionar qualquer elemento com o DevTools. No meu exemplo acima, identifico um item que desejo alterar usando JavaScript e, em seguida, faço algumas alterações nos componentes internos. (Isso significa que estou apenas alterando as coisas dentro da subárvore para esse item da lista.)

DevTools com o item de lista do item em destaque expandido para ver os elementos dentro
Inspecionando um item de lista no DevTools

A aplicação da propriedade contain a um elemento informa ao navegador que as alterações têm como escopo a subárvore desse elemento, para que o navegador possa fazer todas as otimizações possíveis — com a certeza de que nada mais fora desse elemento será alterado. Exatamente o que um navegador em particular pode fazer depende do mecanismo. A propriedade CSS simplesmente oferece a você — como desenvolvedor e especialista nesse layout — a chance de informá-lo.

Em muitos casos, você estará seguro para ir em frente e começar a usar a propriedade contain , no entanto, os diferentes valores vêm com alguns efeitos colaterais potenciais que vale a pena entender antes de adicionar a propriedade aos elementos em seu site.

Usando contenção

A propriedade container pode definir três tipos diferentes de contain :

  • layout
  • paint
  • size

Nota : Existe um valor de style na Especificação de Nível 2. Foi removido do Nível 1, portanto não aparece na Recomendação e não é implementado no Firefox.

Esquema

A contenção de layout traz os maiores benefícios. Para ativar a contenção de layout, use o seguinte snippet:

 .item { contain: layout; }

Com a contenção de layout habilitada, o navegador sabe que nada fora do elemento pode afetar o layout interno, e nada de dentro do elemento pode alterar o layout das coisas fora dele. Isso significa que ele pode fazer todas as otimizações possíveis para esse cenário.

Algumas coisas adicionais acontecem quando a contenção de layout está habilitada. Estas são todas as coisas que garantem que esta caixa e o conteúdo sejam independentes do resto da árvore.

A caixa estabelece um contexto de formatação independente . Isso garante que o conteúdo da caixa permaneça na caixa — em particular, os flutuadores serão contidos e as margens não serão recolhidas pela caixa. Este é o mesmo comportamento que ativamos quando usamos display: flow-root como explicado em meu artigo “Entendendo o layout CSS e o contexto de formatação de bloco”. Se um flutuador pudesse sair de sua caixa, fazendo com que o texto seguinte fluísse ao redor do flutuador, isso seria uma situação em que o elemento estava alterando o layout das coisas fora dele, tornando-o um candidato ruim para contenção.

A caixa de contenção atua como o bloco de contenção para quaisquer descendentes de posição fixa ou absoluta. Isso significa que ele agirá como se você tivesse usado position: relative na caixa que você aplicou contain: layout .

A caixa também cria um contexto de empilhamento . Portanto z-index funcionará nesse elemento, seus filhos serão empilhados com base nesse novo contexto.

Se olharmos para o exemplo, desta vez com o contain: layout , você pode ver que quando o elemento flutuante é introduzido ele não aparece mais na parte inferior da caixa. Este é o nosso novo Contexto de Formatação de Blocos em ação, contendo o float.

Uma lista de itens, um elemento flutuante está contido dentro dos limites da caixa pai
Usando conter: layout o float está contido (Veja o exemplo de contenção de layout no CodePen)

Pintar

Para ativar a contenção de tinta, use o seguinte:

 .item { contain: paint; }

Com a contenção de pintura ativada, ocorrem os mesmos efeitos colaterais vistos com a contenção de layout: a caixa de contenção se torna um contexto de formatação independente, um bloco de contenção para elementos posicionados e estabelece um contexto de empilhamento.

O que a contenção de pintura faz é indicar ao navegador que os elementos dentro do bloco que o contém não serão visíveis fora dos limites dessa caixa. O conteúdo será essencialmente recortado na caixa.

Podemos ver isso acontecer com um exemplo simples. Mesmo se dermos uma altura ao nosso cartão, o item flutuado ainda aparece no fundo da caixa, devido ao fato de que o flutuador é retirado do fluxo.

Uma caixa flutuante saindo do fundo de uma caixa de contenção
O float não está contido no item da lista

Com a contenção de tinta ativada, o item flutuante agora é recortado no tamanho da caixa. Nada pode ser pintado fora dos limites do elemento com contain: paint aplicada.

Uma caixa com uma caixa flutuante dentro da qual foi cortada onde escapa da caixa
O conteúdo da caixa é recortado na altura da caixa (veja o exemplo de pintura no CodePen)

Tamanho

A contenção de tamanho é o valor com maior probabilidade de causar um problema se você não estiver totalmente ciente de como ele funciona. Para aplicar a contenção de tamanho, use:

 .item { contain: size; }

Se você usar contenção de tamanho, estará informando ao navegador que conhece o tamanho da caixa e isso não será alterado. Isso significa que, se você tiver uma caixa dimensionada automaticamente na dimensão do bloco, ela será tratada como se o conteúdo não tivesse tamanho, portanto, a caixa será recolhida como se não tivesse conteúdo.

No exemplo abaixo, não dei uma altura ao li ; eles também contain: size aplicado. Você pode ver que todos os itens foram recolhidos como se não tivessem nenhum conteúdo, criando uma lista de aparência muito peculiar!

Uma lista de itens com um botão para alterar parte do conteúdo do primeiro item
(Veja o exemplo de tamanho no CodePen)

Se você der uma altura às caixas, a altura será respeitada quando contain: size for usado. Por si só, a contenção de tamanho não criará um novo contexto de formatação e, portanto, não contém flutuadores e margens, como a contenção de layout e pintura fará. É menos provável que você o use sozinho; em vez disso, é mais provável que você o aplique junto com outros valores de container para poder obter a maior contain possível.

Valores abreviados

Na maioria dos casos, você pode usar um dos dois valores abreviados para obter o melhor da contenção. Para ativar a contenção de layout e pintura, use o contain: content; , e para ativar toda a contenção possível (tendo em mente que os itens que não têm um tamanho serão recolhidos), use contain: strict .

A Especificação diz:

contain: content é razoavelmente "seguro" para aplicação ampla; seus efeitos são bem menores na prática, e a maior parte do conteúdo não entrará em conflito com suas restrições. No entanto, como ele não aplica contenção de tamanho, o elemento ainda pode responder ao tamanho de seu conteúdo, o que pode fazer com que a invalidação de layout percorra mais acima na árvore do que o desejado. Use container contain: strict quando possível, para obter o máximo de contenção possível.”

Portanto, se você não souber o tamanho dos itens com antecedência e entender o fato de que os floats e as margens estarão contidos, use o contain: content . Se você souber o tamanho dos itens, além de estar feliz com os outros efeitos colaterais da contenção, use contain: strict . O resto fica por conta do navegador, você fez sua parte explicando como seu layout funciona.

Posso usar a contenção agora?

A especificação CSS Containment agora é uma recomendação do W3C, que é o que às vezes chamamos de padrão da web . Para que a especificação chegasse a esse estágio, eram necessárias duas implementações do recurso que podemos ver no Firefox e no Chrome:

Captura de tela das informações de suporte do navegador em Contenção em Posso usar
Suporte do navegador para contenção (Fonte: Posso usar)

Como essa propriedade é transparente para o usuário, é totalmente seguro adicionar a qualquer site mesmo que você tenha muitos visitantes em navegadores que não a suportam. Se o navegador não suportar a contenção, o visitante obtém a experiência que normalmente obtém, aqueles em navegadores de suporte obtêm o desempenho aprimorado.

Eu sugeriria que isso é uma ótima coisa para adicionar a qualquer componente que você crie em um componente ou biblioteca de padrões, se você estiver trabalhando dessa maneira, é provável que cada componente seja projetado para ser uma coisa independente que não afete outros elementos no page, tornando o contain: content uma adição útil.

Portanto, se você tiver uma página que está adicionando conteúdo ao DOM após o carregamento, eu recomendaria experimentá-la - se você obtiver algum resultado interessante, deixe-me saber nos comentários!

Recursos Relacionados

Os recursos a seguir fornecerão mais detalhes sobre a implementação da contenção e os benefícios potenciais de desempenho:

  • “A propriedade CSS contain ”, documentos da web MDN
  • “Contenção de CSS no Chrome 52”, Google Developers
  • “Módulo de Contenção CSS Nível 1”, Recomendação do W3C
  • “Uma introdução à contenção CSS”, Manuel Rego Casasnovas