Enviar um arquivo
  1. base64hub
  2. Aprenda Base64
  3. Desempenho de data URIs
Desempenho

Desempenho de data URIs: quando vale embutir Base64

Embutir um arquivo como data URI em Base64 economiza uma requisição e custa bytes, cache e às vezes tempo de renderização. A compressão muda a conta, e muda de outro jeito para SVG.

O que um data URI custa

Um data URI coloca um arquivo dentro de uma URL: data:image/png;base64,iVBORw0KGgo.... Ele pode ser usado em qualquer lugar onde cabe uma URL, então um ícone pode morar dentro do atributo src do HTML ou de um background-image do CSS, e o navegador nunca faz uma requisição separada para ele.

Os custos são:

  • Tamanho. O Base64 deixa o conteúdo com 4/3 do original, cerca de 33% maior (fórmula exata em acréscimo de tamanho do Base64). O prefixo data:image/png;base64, soma mais 22 bytes.
  • Cache. O arquivo embutido só é cacheado como parte do documento que o contém. Um logo embutido em todas as páginas HTML é baixado de novo com cada página. Embutido num arquivo CSS, ele é cacheado com esse CSS, e trocar um ícone invalida a folha de estilos inteira.
  • Renderização. O navegador não pinta nada até o CSS que bloqueia a renderização chegar. Uma folha de estilos com 200 KB de fontes ou imagens embutidas atrasa a primeira renderização pelo tempo que esses bytes levam para baixar. No HTML, os dados embutidos empurram o conteúdo seguinte mais para baixo no fluxo de bytes.
  • Sem lazy loading. loading="lazy" num <img> com data URI não economiza nada, porque os bytes já chegaram com a página.

Em compensação, você economiza uma requisição. No HTTP/1.1 isso era muita coisa, já que os navegadores abriam só algumas conexões por host. Com HTTP/2 e HTTP/3, muitas requisições compartilham uma conexão, então a economia é menor: basicamente os headers da requisição e da resposta, mais uma ida e volta de latência para arquivos que o navegador descobre tarde.

Medido: o que gzip e Brotli fazem com o Base64

Os 33% valem para texto sem compressão. A maior parte do HTML e do CSS é servida com gzip ou Brotli, então o número que importa é o tamanho compactado. Nós medimos por conta própria.

Método. Arquivos de exemplo de pacotes do Debian 13: um ícone PNG 16×16 (tema de ícones HighContrast), um PNG RGBA 48×48 (tema hicolor), o papel de parede azul do Xfce em JPEG 2880×1800, um JPEG 800×500 redimensionado a partir dele com Pillow na qualidade 80, a fonte Roboto Slab Regular em WOFF2 e dois ícones SVG (um ícone simbólico do Adwaita de 479 bytes e o redemoinho do Debian do GNOME, de 7,6 KB). Cada arquivo e sua codificação Base64 (só o conteúdo, sem o prefixo data:) foram compactados com o zlib do Node.js 24: gzip no nível 9 e Brotli na qualidade 11, as configurações típicas para assets estáticos pré-compactados. Tamanhos em bytes.

ArquivoBrutoBase64Bruto gzipBase64 gzipBruto BrotliBase64 Brotli
PNG 16×16281376285306285284
PNG 48×484,5526,0724,5754,6024,5514,589
JPEG 800×5008,19510,9287,4257,1737,1606,908
JPEG 2880×1800197,011262,684182,684183,945180,114181,140
Fonte WOFF252,53270,04452,53852,76552,53652,690
Ícone SVG479640291427247410
Redemoinho SVG7,61010,1483,1234,3982,5823,823

O que os números mostram:

Binários já compactados perdem quase todo o acréscimo. Dados PNG, JPEG e WOFF2 já são compactados e quase aleatórios, então compactar de novo ganha pouco (os dois PNGs ficaram um pouco maiores com gzip). O Base64 de bytes aleatórios usa 64 símbolos de 8 bits cada, e um codificador Huffman traz isso de volta para cerca de 6 bits por símbolo. O Base64 compactado ficou entre 96% e 107% do binário compactado, e entre 84% e 109% do arquivo bruto. Os JPEGs daqui ainda eram um pouco compactáveis, por isso as versões em Base64 até saíram um pouco menores que o JPEG com gzip; a diferença é pequena demais para entrar no planejamento. No minúsculo PNG 16×16, os 18 bytes fixos de cabeçalho e rodapé do gzip pesam bastante em porcentagem, e o enquadramento mais leve do Brotli os eliminou.

O SVG piora. SVG é texto com muita repetição, e a compressão adora isso: o redemoinho caiu de 7.610 para 3.123 bytes com gzip. O Base64 embaralha cada grupo de 3 bytes em 4 caracteres cujos valores dependem do alinhamento, então uma substring repetida deixa de parecer igual nas duas vezes. O SVG em Base64 com gzip ficou 41–47% maior que o SVG com gzip, e com Brotli, 48–66% maior.

SVG com codificação de URL vs Base64

O SVG nem precisa de Base64, porque já é texto. Um data URI com codificação de URL o mantém legível:

.flag {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3 0v16h2V8h3l1 2h5V2h-4L9 0z'/%3E%3C/svg%3E");
}

O mínimo a escapar é %, # (ele iniciaria um fragmento de URL), < e >, mais o caractere de aspas que delimita o atributo. Trocar as aspas duplas dentro do SVG por aspas simples evita ter que escapá-las. Caracteres não ASCII precisam de codificação percentual como UTF-8.

Os mesmos dois SVGs, medidos do mesmo jeito:

SVGCodificaçãoTamanhoGzipBrotli
ÍconeBase64640427410
ÍconeCodificação de URL mínima493293253
ÍconeencodeURIComponent723326279
RedemoinhoBase6410,1484,3983,823
RedemoinhoCodificação de URL mínima7,1793,0572,549
RedemoinhoencodeURIComponent11,5943,3192,750

“Mínima” significa espaços em branco reduzidos, aspas duplas trocadas por simples e apenas %, #, <, > escapados. Ela compactou para mais ou menos o mesmo tamanho do SVG original; o redemoinho ficou até um pouco menor, porque reduzir os espaços removeu bytes. O encodeURIComponent completo é maior sem compressão, mas ainda compacta muito melhor que o Base64. A ferramenta SVG para data URI gera as duas formas lado a lado.

O Base64 ainda faz sentido para SVG quando uma ferramenta ou API só aceita Base64, ou quando o SVG contém caracteres cujo escape você prefere não ter que pensar.

Content Security Policy e data:

Sob um Content Security Policy, 'self' não inclui URLs data:. Cada diretiva que deve permiti-las precisa listar o esquema:

Content-Security-Policy: default-src 'self'; img-src 'self' data:; font-src 'self' data:

Permitir data: em img-src e font-src é comum e de baixo risco. Permitir em script-src, default-src ou object-src é outra história: isso deixa um atacante que consegue injetar marcação fornecer um script sem precisar de nenhum host externo, o que derruba boa parte do sentido do CSP. Se as imagens embutidas esbarram na sua política, amplie só o img-src.

Os navegadores também impedem que páginas naveguem a janela principal para uma URL data:, seja por link, redirecionamento ou script, então um data URI pode ser embutido numa página, mas não pode ser aberto como link de nível superior.

Quando embutir vale a pena

Geralmente vale:

  • Ícones minúsculos e imagens de interface abaixo de 1–2 KB, mais ou menos, principalmente as necessárias na primeira renderização. O custo da requisição é uma fração grande do tamanho delas, e a compressão apaga quase todo o custo do Base64.
  • HTML em arquivo único. Relatórios offline, documentação exportada, páginas de cobertura de testes e prévias de e-mail em HTML que precisam funcionar quando abertas do disco.
  • CSS crítico que já vai embutido no HTML, onde uma pequena imagem de fundo viaja junto.
  • Conteúdo gerado, como um gráfico renderizado em PNG por um script e embutido num relatório HTML.

Geralmente não vale:

  • Fotos e qualquer coisa acima de alguns kilobytes. Elas funcionam melhor como arquivos separados com cache de longa duração.
  • Imagens compartilhadas por muitas páginas, que seriam baixadas de novo dentro de cada resposta HTML.
  • Fontes web. Um arquivo WOFF2 costuma ter dezenas de kilobytes (o medido acima tem 52 KB); embuti-lo no CSS faz a folha de estilos bloquear a renderização por mais tempo, e arquivos de fonte separados podem ser cacheados e pré-carregados.
  • Qualquer coisa abaixo da dobra. Um arquivo separado com loading="lazy" não custa nada até ser necessário.

E-mail é um caso à parte. O suporte a imagens data: varia entre clientes de e-mail, então teste nos clientes que seus destinatários realmente usam. O jeito confiável de embutir uma imagem num e-mail HTML é um anexo MIME inline referenciado com cid:, que continua sendo Base64, só que dentro da estrutura MIME. Veja Base64 no e-mail.

Crie um data URI a partir de uma imagem

Arraste um PNG, JPEG, WebP ou SVG e receba o data URI e o tamanho dele. O arquivo fica no seu navegador.

Imagem para Base64

Perguntas frequentes

Imagens em Base64 são mais lentas que imagens normais?

Não por natureza. Imagens pequenas embutidas evitam uma requisição, enquanto as grandes incham o HTML ou o CSS, não podem ser cacheadas separadamente e podem atrasar a renderização. Embutir ajuda abaixo de alguns kilobytes e atrapalha acima disso.

O gzip elimina o acréscimo de 33% do Base64?

Para PNG, JPEG e WOFF2, quase totalmente: nas nossas medições o Base64 compactado com gzip ficou a poucos por cento do arquivo binário. Para SVG e outros textos, não: o SVG em Base64 com gzip ficou 41–47% maior que o SVG com gzip.

Para SVG embutido, o que é melhor: codificação de URL ou Base64?

A codificação de URL. Ela é legível, editável e compacta mais ou menos tão bem quanto o SVG original. Escape pelo menos #, %, < e >, e use aspas simples dentro do SVG se o atributo usar aspas duplas.

Por que minhas imagens em data URI são bloqueadas pelo Content Security Policy?

O CSP trata data: como um esquema separado que 'self' não cobre. Adicione data: ao img-src (ou ao font-src para fontes). Não o adicione ao script-src nem ao default-src.

Continue lendo