Melhore o tempo de carregamento inicial ignorando a renderização de conteúdo fora da tela.
Publicado em 5 de agosto de 2020
A propriedade
content-visibility
permite que o
agente do usuário pule o trabalho de renderização de um elemento, incluindo layout e pintura,
até que seja necessário. Como a renderização é ignorada, se uma grande parte do
conteúdo estiver fora da tela, o uso da propriedade content-visibility
vai acelerar o
carregamento inicial do usuário. Ele também permite interações mais rápidas com o
conteúdo na tela. Muito legal.
Confinamento de CSS
O objetivo principal e geral do contenção de CSS é permitir melhorias de desempenho de renderização do conteúdo da Web, fornecendo isolamento previsível de uma subárvore DOM do restante da página.
Basicamente, um desenvolvedor pode informar ao navegador quais partes da página são encapsuladas como um conjunto de conteúdo, permitindo que ele analise o conteúdo sem precisar considerar o estado fora da subárvore. Saber quais partes do conteúdo (subárvores) têm conteúdo isolado significa que o navegador pode tomar decisões de otimização para a renderização da página.
Há quatro tipos de conteiner de
CSS,
cada um um valor potencial para a propriedade CSS contain
, que pode ser combinada
em uma lista de valores separados por espaços:
size
: a contenção de tamanho em um elemento garante que a caixa do elemento possa ser disposta sem precisar examinar os descendentes. Isso significa que podemos pular o layout dos descendentes se tudo o que precisamos é o tamanho do elemento.layout
: contenção de layout significa que os descendentes não afetam o layout externo de outras caixas na página. Isso nos permite pular o layout dos descendentes se quisermos apenas posicionar outras caixas.style
: a contenção de estilo garante que as propriedades que podem ter efeitos em outros elementos além dos descendentes não escapem do elemento (por exemplo, contadores). Isso nos permite pular o cálculo de estilo dos descendentes se tudo que queremos for computar estilos em outros elementos.paint
: a contenção de pintura garante que os descendentes da caixa que contém não apareçam fora dos limites dela. Nada pode transbordar o elemento de forma visível, e, se um elemento estiver fora da tela ou não estiver visível, os elementos filhos também não estarão. Isso permite que possamos pular a pintura dos descendentes se o elemento estiver fora da tela.
Pular a renderização com content-visibility
Pode ser difícil descobrir quais valores de contenção usar, já que as otimizações
do navegador só são ativadas quando um conjunto adequado é especificado. Você pode testar os valores para ver o que funciona melhor ou usar content-visibility
para aplicar a contenção necessária automaticamente. O content-visibility
garante que você receba os maiores
ganhos de desempenho que o navegador pode oferecer com o mínimo de esforço do
desenvolvedor.
A propriedade content-visibility aceita vários valores, mas auto
é o único
que oferece melhorias imediatas no desempenho. Um elemento que tem
content-visibility: auto
ganha a contenção layout
, style
e paint
. Se
o elemento estiver fora da tela e não for relevante para o usuário (elementos
relevantes são aqueles que têm foco ou seleção na subárvore), ele
também recebe a contenção de size
e interrompe
a pintura
e
o teste de hit
do próprio conteúdo.
O que isso significa? Em resumo, se o elemento estiver fora da tela, os descendentes dele não serão renderizados. O navegador determina o tamanho do elemento sem considerar nenhum conteúdo e para por aí. A maior parte da renderização, como o estilo e o layout do subárvore do elemento, é ignorada.
À medida que o elemento se aproxima da janela de visualização, o navegador não adiciona mais a contenção size
e começa a pintar e testar o conteúdo do elemento. Isso
permite que o trabalho de renderização seja feito na hora certa para ser visto pelo usuário.
Observação sobre acessibilidade
Um dos recursos do content-visibility: auto
é que o conteúdo fora da tela permanece disponível no modelo de objeto do documento e, portanto, na árvore de acessibilidade (diferente do visibility: hidden
). Isso significa que o conteúdo pode ser pesquisado na página e navegado sem esperar o carregamento ou sacrificar o desempenho da renderização.
No entanto, o lado negativo é que os elementos de referência com recursos de estilo, como display: none
ou visibility: hidden
, também aparecem na árvore de acessibilidade quando estão fora da tela, já que o navegador não renderiza esses estilos até que eles entrem na viewport. Para evitar que eles fiquem visíveis na árvore de acessibilidade, o que pode causar confusão, adicione aria-hidden="true"
.
Exemplo: um blog de viagens
Um blog de viagens geralmente contém um conjunto de histórias com algumas imagens e texto descritivo. Veja o que acontece em um navegador típico quando ele navega até um blog de viagens:
- Uma parte da página é transferida por download da rede, junto com os recursos necessários.
- O navegador estiliza e organiza todo o conteúdo da página, sem considerar se o conteúdo está visível para o usuário.
- O navegador volta para a etapa 1 até que toda a página e os recursos sejam transferidos por download.
Na etapa 2, o navegador processa todo o conteúdo em busca de coisas que podem ter mudado. Ele atualiza o estilo e o layout de todos os elementos novos, além dos elementos que podem ter mudado como resultado de novas atualizações. Isso é renderizar trabalho. Isso leva tempo.
Agora considere o que acontece se você colocar content-visibility: auto
em cada uma das
histórias individuais no blog. O loop geral é o mesmo: o navegador
faz o download e renderiza partes da página. No entanto, a diferença está no
quanto de trabalho ele realiza na etapa 2.
Com a visibilidade do conteúdo, ele vai estilizar e definir o layout de todos os conteúdos que estão visíveis para o usuário no momento (que estão na tela). No entanto, ao processar a história que está totalmente fora da tela, o navegador pula o trabalho de renderização e só define o estilo e o layout da própria caixa do elemento.
O carregamento dessa página seria como se ela contivesse histórias completas e caixas vazias para cada uma delas. Isso tem um desempenho muito melhor, com redução esperada de 50% ou mais do custo de renderização de carregamento. No nosso exemplo, houve um aumento de um tempo de renderização de 232 ms para 30 ms. Isso representa um aumento de 7 vezes na performance.
Qual é o trabalho que você precisa fazer para colher esses benefícios? Primeiro, dividimos o conteúdo em seções:
Em seguida, aplicamos a seguinte regra de estilo às seções:
.story {
content-visibility: auto;
contain-intrinsic-size: 1000px; /* Explained in the next section. */
}
Especificar o tamanho natural de um elemento com contain-intrinsic-size
Para aproveitar os benefícios potenciais do content-visibility
, o navegador
precisa aplicar a contenção de tamanho para garantir que os resultados de renderização do conteúdo
não afetem o tamanho do elemento de nenhuma forma. Isso significa que o elemento
será exibido como se estivesse vazio. Se o elemento não tiver uma altura especificada
em um layout de bloco regular, ele terá altura 0.
Isso pode não ser ideal, já que o tamanho da barra de rolagem vai mudar, dependendo de cada história ter uma altura diferente de zero.
Felizmente, o CSS oferece outra propriedade, contain-intrinsic-size
, que
especifica efetivamente o tamanho natural do elemento se ele for
afetado pela contenção de tamanho. No nosso exemplo, definimos como 1000px
como
uma estimativa para a altura e a largura das seções.
Isso significa que ele será apresentado como se tivesse um único filho de dimensões "tamanho intrínseco",
garantindo que os divs sem tamanho ainda ocupem espaço.
contain-intrinsic-size
funciona como um tamanho de marcador de posição em vez do conteúdo renderizado.
A palavra-chave auto
para contain-intrinsic-size
faz com que o navegador lembre
o tamanho renderizado pela última vez, se houver, e o use em vez do tamanho do marcador de posição
fornecido pelo desenvolvedor. Por exemplo, se você especificar contain-intrinsic-size: auto 300px
, o
elemento vai começar com um tamanho intrínseco 300px
em cada dimensão, mas, depois
que o conteúdo do elemento for renderizado, ele vai manter o tamanho intrínseco renderizado.
Qualquer alteração subsequente no tamanho de renderização também será lembrada. Na prática, isso significa que, se você
rolar um elemento com content-visibility: auto
aplicado e depois rolar de volta
para fora da tela, ele vai manter automaticamente a largura e a altura ideais, sem reverter
para o tamanho do marcador de posição. Esse recurso é especialmente útil para rolagem infinita,
que agora pode melhorar automaticamente a estimativa de dimensionamento ao longo do tempo à medida que o usuário
explora a página.
Ocultar conteúdo com content-visibility: hidden
E se você quiser manter o conteúdo sem renderização, independentemente de estar ou não
na tela, aproveitando os benefícios do estado de renderização em cache? Insira:
content-visibility: hidden
.
A propriedade content-visibility: hidden
oferece todos os mesmos benefícios de
conteúdo não renderizado e estado de renderização em cache que content-visibility: auto
fora da tela. No entanto, ao contrário do auto
, ele não começa a ser renderizado
automaticamente na tela.
Isso oferece mais controle, permitindo que você oculte o conteúdo de um elemento e o mostre novamente rapidamente.
Compare com outras maneiras comuns de ocultar o conteúdo do elemento:
display: none
: oculta o elemento e destrói o estado de renderização. Isso significa que reexibir o elemento é tão caro quanto renderizar um novo elemento com o mesmo conteúdo.visibility: hidden
: oculta o elemento e mantém o estado de renderização. Isso não remove o elemento do documento de verdade, já que ele (e a subárvore) ainda ocupa espaço geométrico na página e ainda pode ser clicado. Ele também atualiza o estado de renderização sempre que necessário, mesmo quando oculto.
content-visibility: hidden
, por outro lado, oculta o elemento enquanto
preserva o estado de renderização. Portanto, se houver mudanças que precisem
acontecer, elas só vão acontecer quando o elemento for mostrado novamente (ou seja, quando a
propriedade content-visibility: hidden
for removida).
Alguns casos de uso excelentes para content-visibility: hidden
são quando você implementa
roladores virtuais avançados e mede o layout. Elas também são ótimas para
aplicativos de página única (SPAs, na sigla em inglês). As visualizações de apps inativas podem ser deixadas no DOM com
content-visibility: hidden
aplicado para impedir a exibição, mas manter o
estado em cache. Isso torna a renderização da visualização rápida quando ela é ativada novamente.
Efeitos na interação com a próxima pintura (INP)
O INP é uma métrica que avalia a capacidade de resposta confiável de uma página à entrada do usuário. A capacidade de resposta pode ser afetada por qualquer quantidade excessiva de trabalho que ocorra na linha de execução principal, incluindo o trabalho de renderização.
Sempre que você reduz o trabalho de renderização em uma página, você dá à linha de execução principal uma oportunidade de responder às entradas do usuário mais rapidamente. Isso inclui o trabalho de renderização, e o uso da propriedade CSS content-visiblity
, quando apropriado, pode reduzir o trabalho de renderização, especialmente durante a inicialização, quando a maioria do trabalho de renderização e layout é feita.
Reduzir o trabalho de renderização tem um efeito direto na INP. Quando os usuários tentam interagir com uma página que usa a propriedade content-visibility
corretamente para adiar o layout e a renderização de elementos fora da tela, você dá à linha de execução principal a chance de responder a trabalhos essenciais visíveis ao usuário. Isso pode melhorar o INP da sua página em algumas situações.
Conclusão
content-visibility
e a especificação de contenção do CSS significam que alguns recursos
de desempenho incríveis estão chegando ao seu arquivo CSS. Para mais informações sobre essas propriedades, confira: