Melhore o tempo de carregamento inicial pulando 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 tornar a
carga inicial do usuário muito mais rápida. Ele também permite interações mais rápidas com o
conteúdo na tela. Muito legal.
Confinamento de CSS
O objetivo principal e abrangente da contenção do CSS é possibilitar melhorias no desempenho de renderização do conteúdo da Web, fornecendo isolamento previsível de uma subárvore do DOM do restante da página.
Basicamente, um desenvolvedor pode informar a um navegador quais partes da página estão encapsuladas como um conjunto de conteúdo, permitindo que os navegadores pensem sobre o conteúdo sem precisar considerar o estado fora do 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
: o isolamento de layout significa que os descendentes não afetam o layout externo de outras caixas na página. Isso permite que possamos pular o layout dos descendentes se quisermos apenas posicionar outras caixas.style
: o contenção de estilo garante que as propriedades que podem ter efeitos em mais de um elemento não escapem do elemento (por exemplo, contadores). Isso permite que possamos pular a computação de estilo para os descendentes se tudo o que queremos é calcular 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 de navegador só podem entrar em ação quando um conjunto apropriado é 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ê tenha os maiores
ganhos de desempenho que o navegador pode oferecer com o mínimo de esforço da sua parte
como desenvolvedor.
A propriedade de visibilidade do conteúdo aceita vários valores, mas auto
é aquela
que oferece melhorias imediatas de desempenho. Um elemento que tem
content-visibility: auto
ganha contenção layout
, style
e paint
. Se
o elemento estiver fora da tela (e não for relevante para o usuário. Os elementos
relevantes são aqueles que têm foco ou seleção no subárvore), ele
também vai receber contenção size
(e vai parar de
pintar
e
testar acertos
no 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 aí. A maior parte da renderização, como o estilo e o layout da subárvore do elemento, é ignorada.
À medida que o elemento se aproxima da viewport, o navegador não adiciona mais o contêiner size
e começa a pintar e testar o conteúdo do elemento. Isso
permite que o trabalho de renderização seja feito apenas a tempo de 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, possivelmente causando confusão, adicione também 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 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 é o trabalho de renderização. 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 content-visibility, ele vai estilizar e organizar todo o conteúdo que está visível para o usuário (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.
O que você precisa fazer para aproveitar 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 possíveis benefícios do content-visibility
, o navegador
precisa aplicar contenção de tamanho para garantir que os resultados da renderização do conteúdo
não afetem o tamanho do elemento. 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á a altura 0.
Isso pode não ser o ideal, já que o tamanho da barra de rolagem vai mudar, dependendo de que cada história tenha 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á organizado como se tivesse um único filho de dimensões
"intrinsic-size", 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 rolagens infinitas,
que agora podem 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 os mesmos benefícios de
conteúdo não renderizado e estado de renderização em cache que o content-visibility: auto
oferece
fora da tela. No entanto, ao contrário de auto
, ele não começa a renderização
automaticamente na tela.
Isso oferece mais controle, permitindo que você oculte o conteúdo de um elemento e o mostre novamente rapidamente.
Compare-o com outras formas comuns de ocultar o conteúdo do elemento:
display: none
: oculta o elemento e destrói o estado de renderização dele. 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. Ela também atualiza o estado de renderização sempre que é necessário, mesmo quando está 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 acelera a renderização da visualização quando ela fica ativa 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. O uso da propriedade CSS content-visiblity
quando apropriado pode reduzir o trabalho de renderização, especialmente durante a inicialização, quando a maior parte dos trabalhos de renderização e layout é concluído.
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 críticos visíveis para o 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, consulte: