Contenção de CSS no Chrome 52

Texto longo, leia o resumo

A nova propriedade de contenção do CSS permite que os desenvolvedores limitem o escopo dos estilos, layouts e trabalhos de pintura do navegador.

Confinamento do CSS. Antes: o layout leva 59,6 ms. Depois: o layout leva 0,05 ms

Ele tem alguns valores, tornando a sintaxe assim:

    contain: none | strict | content | [ size || layout || style || paint ]

Ele está disponível no Chrome 52 e em versões mais recentes e no Opera 40 e em versões mais recentes (e tem suporte público do Firefox). Teste e nos diga o que achou.

A propriedade contain

Ao criar um app da Web ou até mesmo um site complexo, um dos principais desafios de desempenho é limitar os efeitos de estilos, layout e pintura. Muitas vezes, o todo do DOM é considerado "no escopo" para o trabalho de computação, o que pode significar que tentar uma "visualização" independente em um app da Web pode ser complicado: mudanças em uma parte do DOM podem afetar outras partes, e não há como informar ao navegador o que deve estar dentro ou fora do escopo.

Por exemplo, digamos que parte do DOM tenha esta aparência:

    <section class="view">
      Home
    </section>

    <section class="view">
      About
    </section>

    <section class="view">
      Contact
    </section>

E você anexa um novo elemento a uma visualização, que aciona estilos, layout e pintura:

    <section class="view">
      Home
    </section>

    <section class="view">
      About
      <div class="newly-added-element">Check me out!</div>
    </section>

    <section class="view">
      Contact
    </section>

No entanto, neste caso, o DOM inteiro está no escopo, o que significa que os cálculos de estilo, layout e pintura precisam considerar todos os elementos, independentemente de terem sido alterados ou não. Quanto maior o DOM, mais trabalho de computação ele envolve, o que significa que você pode fazer com que o app não responda à entrada do usuário.

A boa notícia é que os navegadores modernos estão ficando muito inteligentes ao limitar o escopo de estilos, layout e pintura de forma automática, o que significa que as coisas estão ficando mais rápidas sem que você precise fazer nada.

Mas a melhor notícia é que há uma nova propriedade CSS que transfere os controles de escopo para os desenvolvedores: Containment.

O CSS Containment é uma nova propriedade, com a palavra-chave contain, que aceita quatro valores:

  • layout
  • paint
  • size
  • style

Cada um desses valores permite limitar a quantidade de trabalho de renderização que o navegador precisa fazer. Vamos analisar cada um deles com mais detalhes.

Layout (contain: layout)

O contenção de layout é provavelmente o maior benefício da contenção, junto com contain: paint.

O layout normalmente tem escopo de documento, o que faz com que ele seja dimensionado proporcionalmente ao tamanho do DOM. Portanto, se você mudar a propriedade left de um elemento, talvez seja necessário verificar cada elemento no DOM.

Ativar a contenção aqui pode reduzir o número de elementos para apenas alguns, em vez de todo o documento, economizando muito trabalho desnecessário no navegador e melhorando significativamente o desempenho.

Tinta (contain: paint)

A pintura de escopo é outro benefício incrivelmente útil da contenção. A contenção de pintura basicamente corta o elemento em questão, mas também tem alguns outros efeitos colaterais:

  • Ele atua como um bloco que contém elementos de posição absoluta e fixa. Isso significa que todos os filhos são posicionados com base no elemento com contain: paint, e não em qualquer outro elemento pai, como o documento.
  • Ele se torna um contexto de empilhamento. Isso significa que elementos como z-index vão ter um efeito no elemento, e os filhos vão ser empilhados de acordo com o novo contexto.
  • Ele se torna um novo contexto de formatação. Isso significa que, se você tiver, por exemplo, um elemento de nível de bloco com contenção de pintura, ele será tratado como um novo ambiente de layout independente. Isso significa que o layout fora do elemento normalmente não afeta os filhos do elemento que o contém.

Tamanho (contain: size)

O que contain: size significa é que os filhos do elemento não afetam o tamanho do pai, e que as dimensões inferidas ou declaradas serão as usadas. Consequentemente, se você definir contain: size, mas não especificar as dimensões do elemento (diretamente ou usando propriedades flex), ele será renderizado em 0 px por 0 px.

A contenção de tamanho é uma medida de segurança para garantir que você não dependa de elementos filhos para dimensionar, mas, por si só, não oferece muitos benefícios de desempenho.

Estilo (contain: style)

Pode ser difícil prever quais serão os efeitos na árvore do DOM de mudar os estilos de um elemento. Um exemplo disso é o uso de contadores CSS, em que a alteração de um contador em um elemento filho pode afetar os valores de contador do mesmo nome usados em outro lugar do documento. Com o contain: style definido, as mudanças de estilo não são propagadas para além do elemento que contém.

Para deixar bem claro, o que o contain: style não fornece é o estilo de escopo que você teria do Shadow DOM. O que é contido aqui é apenas limitar as partes da árvore que estão em consideração quando os estilos são modificados, não quando eles são declarados.

Contenção rígida e de conteúdo

Também é possível combinar palavras-chave, como contain: layout paint, que aplicam apenas esses comportamentos a um elemento. Mas o contain também aceita dois outros valores:

  • contain: strict significa o mesmo que contain: size layout paint
  • contain: content significa o mesmo que contain: layout paint

O uso da contenção estrita é ótimo quando você sabe o tamanho do elemento com antecedência (ou quer reservar as dimensões dele), mas lembre-se de que, se você declarar a contenção estrita sem dimensões, devido à contenção de tamanho implícita, o elemento poderá ser renderizado como uma caixa de 0 px por 0 px.

Por outro lado, a contenção de conteúdo oferece melhorias significativas no escopo, mas não exige que você saiba ou especifique as dimensões do elemento com antecedência.

Dos dois, contain: content é o que você deve usar por padrão. Você deve tratar o contenção estrito como uma escotilha de fuga quando contain: content não for forte o suficiente para suas necessidades.

Mostre para a gente como você está usando ele!

O contenção é uma ótima maneira de começar a indicar ao navegador o que você pretende manter isolado na página. Faça um teste no Chrome 52 ou versão mais recente e nos diga o que achou.