Há pouco mais de um ano, a equipe do Chrome Aurora lançou a diretiva NgOptimizedImage do Angular. A diretiva tem como foco principal a melhoria do desempenho, conforme avaliado pelas Core Web Vitals. Ela agrupa otimizações de imagem comuns e práticas recomendadas em uma API voltada ao usuário que não é muito mais complicada do que um elemento <img>
padrão.
Em 2023, aprimoramos a diretiva com novos recursos. Esta postagem descreve os recursos mais substanciais desses novos recursos, com ênfase no motivo pelo qual escolhemos priorizar cada recurso e como isso pode ajudar a melhorar o desempenho dos aplicativos do Angular.
Novos recursos
O NgOptimizedImage melhorou significativamente com o tempo, incluindo os novos recursos a seguir.
Modo de preenchimento
Dimensionar suas imagens fornecendo atributos width
e height
é uma otimização extremamente importante para reduzir a mudança de layout, porque os navegadores precisam saber a proporção da imagem para economizar espaço para ela. No entanto, o dimensionamento de imagens é um trabalho adicional para desenvolvedores de aplicativos e não faz sentido em alguns casos de uso de imagem.
O modo de preenchimento é o primeiro recurso importante adicionado ao componente de imagem após a prévia para desenvolvedores para ajudar a resolver essa tensão. Essa é uma forma dos desenvolvedores incluirem imagens sem dimensioná-las explicitamente e sem mudança de layout.
No modo de preenchimento, o requisito de tamanho da imagem fica desativado, e a imagem é estilizada automaticamente para preencher o elemento que a contém. Isso separa a proporção de uma imagem do espaço que ela ocupa na página e oferece maior controle sobre como as imagens se encaixam no layout da página.
O modo de preenchimento usa NgOptimizedImage como uma alternativa de melhor performance à propriedade CSS background-image
. Coloque uma imagem dentro da <div>
ou de outro elemento que teria o estilo background-image
e ative o modo de preenchimento, conforme demonstrado no exemplo de código anterior. Use as propriedades CSS object-fit
e object-position
no <div>
para controlar como a imagem é posicionada em segundo plano.
// Height and width are required
<img ngSrc="example.com" height="300" width="400">
// Unless you use fill mode!
<div style="width: 100vw; height: 50em; position: relative">
<img ngSrc="example.com" fill>
</div>
Geração de Srcset
Uma das técnicas mais eficazes de otimização de imagens é o uso do atributo srcset
para garantir que imagens de tamanho adequado sejam transferidas por download para qualquer dispositivo que acesse seu aplicativo. Usar o srcset
em todo o app pode evitar o desperdício de largura de banda e melhorar bastante a Core Web Vitals da LCP.
A desvantagem do atributo srcset
é que a implementação dele pode ser complicada. Gravar valores srcset
manualmente significa adicionar várias linhas de marcação a cada elemento de imagem no app, com vários URLs personalizados para cada srcset
. Também é preciso decidir sobre um conjunto de pontos de interrupção, o que é complicado, já que eles podem representar as densidades de tela e os tamanhos da janela de visualização de dispositivos comuns.
Por isso, adicionar a geração de srcset automatizada à diretiva NgOptimizedImage foi um marco importante após o lançamento. Com essa adição, qualquer aplicativo que use uma CDN compatível com redimensionamento de imagem poderá ter srcsets completas e personalizáveis adicionadas automaticamente a cada imagem gerada com a diretiva NgOptimizedImage.
Incluímos uma API simplificada para definir a propriedade sizes
, que é usada para garantir que cada imagem receba o tipo correto de srcset
. Se você não incluir um atributo sizes
, saberemos que a imagem precisa ter um tamanho fixo e receberá um srcset dependente de densidade, como mostrado abaixo:
<img src="www.example.com/image.png" srcset="www.example.com/image.png?w=400 1x, www.example.com/image.png?w=800 2x" >
Esse tipo de srcset garante que as imagens sejam veiculadas em um tamanho que leve em consideração a densidade de pixels do dispositivo do usuário.
Por outro lado, se você incluir a propriedade sizes
, o NgOptimizedImage
gera um srcset responsivo que inclui pontos de interrupção para vários tamanhos comuns de dispositivos e imagens, usando esta lista padrão de pontos de interrupção:
[16, 32, 48, 64, 96, 128, 256, 384, 640, 750, 828, 1080, 1200, 1920, 2048, 3840]
Geração de pré-conexão
Para melhorar a LCP, é importante reduzir o tempo que os usuários passam fazendo o download da imagem de LCP. Na seção anterior, você aprendeu como o srcset
pode ajudar transferindo arquivos de imagem menores, mas uma otimização igualmente importante é iniciar a transferência o mais rápido possível. Uma maneira de fazer isso é usando tags link rel="preconnect"
para iniciar a conexão com o domínio da imagem.
Desde o início, o NgOptimizedImage avisa se você não conseguir se pré-conectar ao domínio da imagem LCP, mas aviso não é a solução ideal. Preferimos apenas corrigir o problema para você. É exatamente isso que a NgOptimizedImage agora faz, com a geração de pré-conexão automatizada.
Para oferecer suporte a esse recurso, usamos a análise de código estático para tentar detectar domínios de imagem em carregadores NgOptimizedImage e gerar automaticamente tags de link de pré-conexão para esses domínios. Ainda pode haver casos em que os links de pré-conexão manual sejam necessários, mas, para a maioria dos usuários, a pré-conexão automática significa uma etapa a menos necessária para um bom desempenho da imagem.
Suporte avançado a carregadores personalizados
Um elemento-chave de NgOptimizedImage é a arquitetura de carregador, que permite que a diretiva gere automaticamente URLs adaptados à CDN de imagem do aplicativo. Um conjunto de carregadores integrados está incluído para CDNs amplamente usadas. Também fornecemos o uso de carregadores personalizados, que permitem integrar o NgOptimizedImage a praticamente qualquer solução de hospedagem de imagens.
No lançamento, esses carregadores personalizados tinham escopo limitado e só podiam ler o atributo width
do elemento de imagem. Em resposta ao feedback dos usuários, adicionamos suporte a uma estrutura de dados loaderParams
personalizável, que permite que dados arbitrários sejam transmitidos do elemento de imagem para o carregador personalizado. Com a expansão, os carregadores personalizados podem ser tão simples ou complexos quanto exigido pela infraestrutura de imagem de um aplicativo.
O exemplo a seguir mostra como um carregador personalizado simples pode usar a API loaderParams
para selecionar entre dois domínios de imagem alternativos:
const myCustomLoader = (config: ImageLoaderConfig) => {
if (config.loaderParams?.alternateDomain) {
return `https://alternate.domain.com/images/${config.src}`
}
return `https://primary.domain.com/images/${config.src}`;
};
Um exemplo de um carregador personalizado mais complexo está disponível na documentação do Angular (em inglês).
Orientações expandidas sobre o desempenho da imagem
Até agora, todos os alertas de desempenho de imagem que adicionamos ao Angular faziam parte da diretiva NgOptimizedImage. Se você não usar a diretiva no app, não vai receber orientações sobre problemas de desempenho da imagem.
No Angular 17, estamos expandindo o escopo das orientações sobre desempenho de imagem para incluir todos os aplicativos do Angular. Se detectarmos padrões de imagem que sabemos que são erros que prejudicam o desempenho, como o carregamento lento da imagem da LCP ou o download de um arquivo muito grande para a página, informaremos você, mesmo que não esteja usando o NgOptimizedImage.
O desempenho das imagens é importante para todos os apps, e estamos felizes em continuar criando proteções para ajudar a evitar erros comuns nos apps do Angular.
Para o futuro
Já estamos trabalhando duro no desenvolvimento do próximo conjunto de recursos para NgOptimizedImage. Embora o desempenho das imagens continue sendo nossa preocupação central, também gostaríamos de adicionar recursos que melhorem a experiência do desenvolvedor para garantir que o NgOptimizedImage continue sendo uma opção atrativa para incluir imagens em aplicativos Angular.
Um recurso que é uma prioridade para nós são os espaços reservados para imagens. Eles são comumente usados para melhorar a aparência do carregamento de imagens em aplicativos da Web, mas podem prejudicar o desempenho se implementados incorretamente. Esperamos criar um sistema de marcador de posição de imagem com foco no desempenho na NgOptimizedImage. Fique de olho no nosso blog para mais anúncios.