O ResizeObserver
informa quando o tamanho de um elemento muda.
Antes de ResizeObserver
, era preciso anexar um listener ao resize
do documento
para receber notificações sobre qualquer alteração nas dimensões da janela de visualização. No evento
de eventos, você teria que descobrir quais elementos foram afetados pelo
que mudam e chamam uma rotina específica para reagir adequadamente. Se você precisasse
as novas dimensões de um elemento após um redimensionamento, era preciso chamar
getBoundingClientRect()
ou getComputedStyle()
, o que pode causar o layout
se você não agrupar todas as leituras e todas as suas
gravações.
Isso nem mesmo abordou os casos em que os elementos mudavam de tamanho sem a parte principal
foi redimensionada. Por exemplo, anexar novos filhos, definir uma
o estilo display
do elemento para none
, ou ações semelhantes podem mudar o tamanho
um elemento, seus irmãos ou seus ancestrais.
É por isso que ResizeObserver
é um primitivo útil. Ele reage a mudanças
tamanho de qualquer um dos elementos observados, independentemente do que causou a alteração.
Ela também fornece acesso ao novo tamanho dos elementos observados.
API
Todas as APIs com o sufixo Observer
mencionado acima compartilham uma API simples
do projeto. ResizeObserver
não é exceção. Você cria um objeto ResizeObserver
e passar um retorno de chamada para o construtor. O retorno de chamada recebe uma matriz de
objetos ResizeObserverEntry
, uma entrada por elemento observado, que
contém as novas dimensões do elemento.
var ro = new ResizeObserver(entries => {
for (let entry of entries) {
const cr = entry.contentRect;
console.log('Element:', entry.target);
console.log(`Element size: ${cr.width}px x ${cr.height}px`);
console.log(`Element padding: ${cr.top}px ; ${cr.left}px`);
}
});
// Observe one or multiple elements
ro.observe(someElement);
Alguns detalhes
O que está sendo informado?
Geralmente, uma
ResizeObserverEntry
informa a caixa de conteúdo de um elemento por meio de uma propriedade chamada
contentRect
, que retorna uma
DOMRectReadOnly
objeto. A caixa de conteúdo é aquela em que o conteúdo pode ser colocado. É
a caixa de borda menos o preenchimento.
É importante observar que enquanto ResizeObserver
informa as duas dimensões
do contentRect
e do padding, ele só observa o contentRect
.
Não confunda contentRect
com a caixa delimitadora do elemento. O elemento delimitador
, como relatado por getBoundingClientRect()
, é a caixa que contém o
o elemento inteiro e os descendentes dele. Os SVGs são uma exceção à regra, em que
ResizeObserver
informará as dimensões da caixa delimitadora.
A partir do Chrome 84, o ResizeObserverEntry
tem três novas propriedades para oferecer mais
informações detalhadas. Cada uma dessas propriedades retorna um ResizeObserverSize
.
que contém uma propriedade blockSize
e uma propriedade inlineSize
. Isso
são sobre o elemento observado no momento em que a chamada de retorno é invocada.
borderBoxSize
contentBoxSize
devicePixelContentBoxSize
Todos esses itens retornam matrizes somente leitura porque, no futuro, espera-se que eles podem oferecer suporte a elementos com vários fragmentos, que ocorrem em de várias colunas. Por enquanto, essas matrizes vão conter apenas um elemento.
A compatibilidade com a plataforma para essas propriedades é limitada, mas o Firefox já oferece suporte as duas primeiras.
Quando ela está sendo informada?
A especificação determina que ResizeObserver
precisa processar todos os eventos de redimensionamento
antes da pintura e depois do layout. Isso torna o callback de um ResizeObserver
lugar ideal para fazer alterações no layout da página. Porque ResizeObserver
o processamento ocorre entre o layout e a pintura. Isso apenas invalida
o layout, não a pintura.
Entendi
Você pode estar se perguntando: o que acontece se eu mudar o tamanho de uma área
dentro do callback para ResizeObserver
? A resposta é: você acionará
outra chamada para o retorno imediatamente. Felizmente, o ResizeObserver
tem um
para evitar loops infinitos de callback e dependências cíclicas. As mudanças vão
ser processados apenas no mesmo frame se o elemento redimensionado estiver mais profundo no DOM
do que o elemento shallowest processado no callback anterior.
Caso contrário, eles serão adiados para o próximo frame.
Aplicativo
Uma coisa que ResizeObserver
permite que você faça é implementar por elemento
consultas de mídia. Observando os elementos, é possível definir de modo imperativo
projetar pontos de interrupção e mudar os estilos de um elemento. Nos seguintes
example, a segunda caixa
alterará o raio da borda de acordo com a largura.
const ro = new ResizeObserver(entries => {
for (let entry of entries) {
entry.target.style.borderRadius =
Math.max(0, 250 - entry.contentRect.width) + 'px';
}
});
// Only observe the second box
ro.observe(document.querySelector('.box:nth-child(2)'));
Outro exemplo interessante é a janela de bate-papo. O problema que surge em um layout típico de conversa, de cima para baixo, é o posicionamento de rolagem. Para evitar o usuário, é útil se a janela ficar na parte inferior do em que as mensagens mais recentes aparecem. Além disso, qualquer tipo de layout mudar (pense em um celular mudando do modo paisagem para retrato ou vice-versa) conseguem o mesmo.
A ResizeObserver
permite escrever apenas um trecho de código que cuida
os dois cenários. O redimensionamento da janela é um evento que uma ResizeObserver
pode
capture por definição, mas chamar appendChild()
também redimensiona esse elemento.
(a menos que overflow: hidden
esteja definido), porque ele precisa criar espaço para o novo
os elementos. Com isso em mente, são necessárias poucas linhas para atingir o
efeito:
const ro = new ResizeObserver(entries => {
document.scrollingElement.scrollTop =
document.scrollingElement.scrollHeight;
});
// Observe the scrollingElement for when the window gets resized
ro.observe(document.scrollingElement);
// Observe the timeline to process new messages
ro.observe(timeline);
Interessante, não é?
A partir daqui, posso adicionar mais código para lidar com o caso em que o usuário rolou a tela manualmente e quer que a rolagem seja imposta à mensagem quando uma nova mensagem novos dados chegam.
Outro caso de uso é para qualquer tipo de elemento personalizado que esteja fazendo o próprio layout.
Até ResizeObserver
, não havia uma maneira confiável de receber notificações de quando seus
as dimensões mudam para que os filhos
possam ser dispostos novamente.
Efeitos na interação com a próxima exibição (INP, na sigla em inglês)
Interaction to Next Paint (INP) é uma métrica que mede a capacidade de resposta geral de uma página para as interações do usuário. Se o INP de uma página estiver em as boas limite, ou seja, 200 milissegundos ou menos, é possível dizer que a página responde de forma confiável ao as interações do usuário com ele.
O tempo necessário para executar callbacks de eventos em resposta a uma interação do usuário podem contribuir significativamente para a latência total de uma interação, esse não é o único aspecto da INP a ser considerado. A INP também considera a quantidade o tempo que leva para a next paint da interação ocorrer. Esta é a o tempo que leva para o trabalho de renderização necessário para atualizar o usuário interface em resposta a uma interação para ser concluída.
No caso de ResizeObserver
, isso é importante porque o callback que
uma instância do ResizerObserver
é executada logo antes do trabalho de renderização. Isso
ocorre por padrão, já que o trabalho que ocorre no callback precisa ser levado
conta, pois esse trabalho provavelmente exigirá uma alteração na
de uma ferramenta de visualização.
Tome cuidado para reduzir o trabalho de renderização necessário em um ResizeObserver
.
já que o excesso de trabalho de renderização pode criar situações em que o navegador
atrasa a realização de um trabalho importante. Por exemplo, se alguma interação tem um
callback que gera a execução de um callback ResizeObserver
, verifique se você está fazendo o
a seguir para facilitar a experiência:
- Use os seletores de CSS o mais simples possível para evitar recálculo de estilo excessivo. Os recálculos de estilo ocorrem pouco antes do layout, e seletores de CSS complexos podem atrasar as operações de layout.
- Evite fazer qualquer trabalho no callback
ResizeObserver
que possa ser acionado reflows forçados. - O tempo necessário para atualizar o layout de uma página geralmente aumenta com o
número de elementos DOM em uma página. Embora isso seja verdade independentemente de as páginas usarem ou não
ResizeObserver
, o trabalho feito em um callbackResizeObserver
pode se tornar significativo à medida que a complexidade estrutural da página aumenta.
Conclusão
O ResizeObserver
está disponível em todas as principais
navegadores
e fornece uma maneira eficiente de monitorar o redimensionamento de elementos em um elemento
nível No entanto, tome cuidado para não atrasar muito a renderização com essa API eficiente.