A regra prática
Embuta uma imagem quando o custo de uma requisição separada for maior que o custo dos bytes extras. Com as conexões HTTP/2 e HTTP/3 atuais, requisições extras são baratas, então esse ponto chega cedo: um bom limite de trabalho é de 2 a 4 KB por imagem. As ferramentas de build mais populares concordam; o Vite embute por padrão arquivos abaixo de 4 KB e os asset modules do webpack, abaixo de 8 KB.
A ferramenta abaixo transforma um PNG (ou qualquer imagem) em data URI. Solte a imagem ou abra o arquivo e escolha como copiar em Copiar como: Data URI, Base64 puro, uma linha CSS de background-image pronta, uma tag img do HTML com largura e altura ou Markdown. Ela mostra o tamanho do data URI e quanto ele ficou maior que o arquivo, e avisa quando o resultado é grande a ponto de deixar uma página lenta. As imagens são convertidas no seu navegador e nunca são enviadas.
Experimente aqui: PNG para Base64
Abrir a página completa da ferramentaO que acontece quando você embute uma imagem
Um data URI como data:image/png;base64,iVBORw0KGgo... coloca os bytes da imagem dentro do HTML, do CSS ou do JSON que a referencia. O navegador recebe a imagem junto com esse arquivo, sem download separado. Esse é todo o benefício. Os custos vêm do mesmo fato:
- Tamanho: o Base64 escreve 3 bytes como 4 caracteres, então a imagem cresce cerca de um terço. A compressão Gzip ou Brotli no servidor recupera parte disso na transferência, mas não tudo, e imagens que já são comprimidas (PNG, JPG, WebP) ganham pouco.
- Cache: um arquivo de imagem separado fica em cache uma vez e é reaproveitado em todas as páginas. Uma imagem embutida só fica em cache como parte do arquivo que a contém. Mude uma linha do CSS e todos os ícones embutidos são baixados de novo.
- Bloqueio de renderização: o CSS bloqueia a primeira pintura. Cada kilobyte de imagem embutida numa folha de estilo atrasa o momento em que algo aparece na tela, mesmo que essas imagens estejam lá no fim da página.
- Sem lazy loading: loading="lazy" e as escolhas responsivas de srcset perdem o sentido, porque os bytes já chegaram com a página.
- Manutenção: uma string Base64 longa é ilegível na revisão de código e fácil de quebrar com uma cópia malfeita.
Guia de tamanho: embutir ou arquivo separado?
| Imagem | Tamanho típico do arquivo | Em Base64 | Recomendação |
|---|---|---|---|
| Ícone de interface de 16 a 24 px (PNG ou SVG) | 200 bytes a 1 KB | cerca de 0,3 a 1,4 KB | Embutir, caso ideal |
| Logo pequeno ou selo | 2 a 5 KB | cerca de 2,7 a 6,7 KB | Embutir se for usado em uma página só ou numa assinatura de e-mail, senão arquivo |
| Placeholder desfocado de uma foto | 300 bytes a 1 KB | cerca de 0,4 a 1,4 KB | Embutir e depois carregar a foto real como arquivo |
| Logo usado em todas as páginas | 10 a 30 KB | cerca de 13 a 40 KB | Arquivo separado, para ficar em cache uma vez |
| Foto de produto ou imagem de destaque | 50 a 500 KB | cerca de 67 a 670 KB | Arquivo separado com lazy loading ou preload |
Bons usos para imagens em Base64
- Ícones pequenos no CSS, como setas, marcas de seleção, um checkbox personalizado ou a seta de um select, que precisam aparecer junto com os estilos e nunca surgir atrasados.
- Entregas em arquivo único: um relatório HTML, uma fatura exportada, uma página de documentação ou um protótipo que precisa funcionar aberto direto do disco ou enviado como um único anexo.
- APIs e bancos de dados: o JSON não tem tipo binário, então imagens em requisições e respostas de API (assinaturas, avatares, documentos digitalizados, fotos de produto em algumas integrações com marketplaces) costumam ir como strings Base64.
- Placeholders de baixa qualidade: uma versão minúscula e desfocada embutida no HTML aparece na hora enquanto a imagem completa carrega.
- Ícones SVG: SVG é texto, então muitas vezes nem precisa de Base64. A opção Codificação para URL em vez de Base64 da ferramenta mantém o SVG legível e geralmente dá um resultado mais curto.
Quando evitar
- Fotos e qualquer imagem acima de uns 10 KB numa página da web. Use um arquivo normal em WebP ou AVIF, com largura e altura definidas e lazy loading para as imagens abaixo da primeira tela.
- A maior imagem do topo da página (o elemento LCP). Uma imagem grande embutida deixa o próprio HTML pesado e atrasa todo o resto; fazer preload de um arquivo separado costuma ser mais rápido.
- Imagens repetidas em várias páginas, como o logo do site ou um padrão de fundo. O cache vale mais do que economizar uma requisição.
- E-mail HTML para o público em geral. Muitos clientes de e-mail não exibem imagens em data URI; Gmail e Outlook para Windows são os mais conhecidos. Use imagens hospedadas ou anexos referenciados por content ID (CID). Data URIs embutidos funcionam principalmente no Apple Mail e em alguns aplicativos de celular, o que não basta para uma newsletter.
- Data URIs muito grandes em geral. O antigo Internet Explorer 8 limitava a 32 KB; os navegadores modernos aceitam bem mais, mas o desempenho sofre muito antes de chegar a qualquer limite.
Como fazer do jeito certo
Reduza a imagem antes de converter. Cada byte economizado é multiplicado por 4/3 no data URI, então comprima os ícones PNG, redimensione imagens grandes demais para o tamanho em que aparecem e, para fotos que você precisa embutir, como num payload JSON, use JPG ou WebP com uma qualidade razoável. O compressor e o redimensionador de imagens deste site fazem isso no navegador, e você pode trazer o arquivo menor de volta para cá.
Inclua as dimensões. Uma tag img sem width e height faz o layout pular quando a imagem aparece. Por isso a saída HTML desta ferramenta inclui a largura e a altura reais da imagem.
Guarde o arquivo de origem. Mantenha o PNG ou SVG original no projeto e gere o data URI a partir dele, com a sua ferramenta de build ou com esta ferramenta quando algo mudar. Nunca trate a string Base64 como a cópia principal.
Meça. Compare a página com e sem as imagens embutidas no painel Rede do navegador ou com o Lighthouse. Se o arquivo CSS ou HTML crescer bastante e nada ficar mais rápido, volte para um arquivo separado.