Ana içeriğe geç

Data URI Scheme Nedir? HTML'de Resim Gömme

Data URI Scheme Nedir? HTML'de Resim Gömme - Web Geliştirme Rehberi

Data URI Scheme, harici bir URL'ye referans vermek yerine verinin kendisini doğrudan kaynak değeri olarak kullanır. Tarayıcı ağa çıkmaz; string bellekte çözümlenir, HTTP isteği başlamadan önce resim işlenmiş olur.

Teknik meşru ve belgelidir. Ama çoğu anlatı "hızlı ve kolay" kısmında duruyor; hangi bağlamda değer taşıdığı, hangi bağlamda tersine işlediği çok daha az ele alınıyor.

Data URI sözdizimi ve format yapısı

Data URI şu sözdizimini izler:

data:[mediatype];[encoding],[data]

Gerçek bir PNG için bu şöyle görünür:

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==

İlk bölüm medya tipini bildirir: image/png, image/jpeg, image/svg+xml, image/webp. Ardından encoding türü gelir — çoğu resim için bu base64. Son kısım ise encode edilmiş veri. Bir dosyayı Base64 formatına dönüştürmek için encode aracını kullanabilirsiniz; elde edilen string doğrudan src veya url() içine yapıştırılabilir.

Önemli bir ayrım: base64 kısmı zorunlu değildir. Düz metin içerik — SVG gibi — charset=utf-8 ile URL-encoded biçimde de iletilebilir; binary veriyi metin kanalıyla güvenle taşımanın yolu Base64 olduğu için resim dosyaları neredeyse her zaman bu encoding'i kullanır.

Yanlış yazılmış bir Data URI tarayıcı tarafından sessizce atlanır — resim yüklenmez, konsola genellikle belirsiz bir ağ hatası düşer. En sık karşılaşılan durum: başlığın image/png demesi ama verinin JPEG kodlanmış olması, ya da Base64 string'inin ortasında satır sonu karakteri kalması. Bu tür hatalar geliştirme ortamında gözden kaçar; tarayıcı hatalı string'i atlayıp boş görsel alanı bırakır.

img etiketinde Data URI kullanımı

<img> etiketinin src niteliği harici URL yerine Data URI kabul eder:

<img src="data:image/png;base64,iVBORw0KGgo..." alt="küçük ikon">

Tarayıcı bu satırı gördüğünde HTTP isteği başlatmaz; string'i doğrudan bellekte çözümler. Resim sayfa yüklendiğinde zaten işlenmiş olur — sunucuya gidip gelmeden, bağlantı gecikmesi olmadan.

Büyük bir hero görseli için aynı tekniği uygulamak ise farklı bir sonuç doğurur. HTML dosyası şişer, tarayıcının HTML parser'ı uzun bir Base64 bloğunu işlemek zorunda kalır; bu süre boyunca sonraki DOM yapısının oluşturulması bekler. 20KB üzerindeki görseller için bu parse maliyeti LCP ölçümüne doğrudan yansır — kullanıcı sayfanın "hazır" görünmesini beklerken aslında parser'ın encode bloğunu tüketmesini bekler.

CSS'de background-image ve SVG gömme

CSS'de background-image özelliği de Data URI alır:

.icon-check {
  background-image: url("data:image/svg+xml;base64,PHN2Zy...");
  width: 16px;
  height: 16px;
}

SVG ikonları için bu yöntem özellikle pratiktir. Bir CSS dosyasında birden fazla Data URI tanımı yapılabilir; stil dosyası sunucudan çekildiğinde tüm görseller de gelir, ek istek gerekmez.

Ancak CSS dosyasının kendisi şişer. Gzip veya Brotli sıkıştırma bu büyümeyi kısmen dengeler — sorun şurada: dosya her değiştiğinde tarayıcı cache'i geçersiz olur, sadece resim değil tüm CSS yeniden indirilir. Küçük ikonlar için bu birliktelik kazanç sağlayabilir; büyük görseller için ise cache stratejisini doğrudan bozar.

SVG metin tabanlı bir format olduğundan, Base64 encode etmeden URL-encoding ile gömmek de mümkündür:

background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E...%3C/svg%3E");

Bu yöntemin Base64'e göre net bir avantajı var: boyut artışı yaşanmaz. SVG zaten metin, encode edilmeden taşınır; Gzip sıkıştırması da metin üzerinde daha verimli çalışır.

Alternatif olarak SVG kodu doğrudan HTML'e inline yazılabilir — bu durumda Data URI formatına bile gerek kalmaz. Inline SVG, JavaScript ile dinamik renk veya animasyon kontrolü gerektiren durumlarda ek bir avantaj sağlar; ama HTML boyutunu büyütür ve farklı bileşenler arasında paylaşımı zorlaştırır.

Data URI'nin boyut ve performans dengesi

Base64 encoding her 3 byte'ı 4 karaktere çevirir. Bu matematiksel dönüşüm sabittir: yaklaşık %33 boyut artışı kaçınılmaz. Sunucu sıkıştırması farkı küçültür, ama orijinal binary dosyadan büyük kalır.

Bir senaryoyu somutlaştıralım. 4KB boyutunda bir PNG ikonunuz var. Base64 encode edildiğinde yaklaşık 5.3KB olur — gzip sonrası belki 4.2–4.5KB arasında. Bu ikon artık HTML veya CSS dosyasının içindedir; sayfanın yüklendiği her durumda bellekte yer kaplar, görüntülenmeyecek sayfada bile. Harici bir dosyada olsaydı tarayıcı sadece gerektiğinde çekerdi.

HTTP/2 bağlamında bu denge değişti. HTTP/1.1 döneminde her istek pahalıydı; Data URI ile istekleri birleştirmek net bir kazanç sağlıyordu. HTTP/2, çoklu isteği tek bağlantı üzerinden eş zamanlı gönderebildiği için "istek sayısını azaltır" argümanı artık her bağlamda geçerli değil.

LCP açısından durum daha da nettir. Büyük görselleri Data URI ile HTML içine gömmek, tarayıcının parse aşamasında yüklü bir Base64 bloğunu çözmesini zorunlu kılar; bu işlem, harici bir WebP dosyasını HTTP/2 üzerinden paralel indirmekten çoğunlukla daha yavaştır. Hero görseli gibi LCP adayı olan bir resmi HTML'e gömmek, teorik "istek azaltma" kazancından çok daha yüksek bir parse maliyeti getirebilir.

Büyük görsellerde Data URI yerine harici dosyayı tercih edip boyutu küçültmek çoğu zaman daha mantıklıdır. Modern formata (WebP veya AVIF) geçerek dosya boyutunu düşürmek, ek bir HTTP/2 isteğinin maliyetini fazlasıyla karşılar.

Karıştırılan mekanizmalar: inline SVG ve Blob URL

Data URI ile sıkça karıştırılan iki mekanizma var. İkisi de "dosyayı dışarıdan çekme" adımını devre dışı bırakıyor gibi görünse de teknik işleyişleri farklı.

Inline SVG doğrudan HTML'e <svg> etiketi olarak yazılır — Data URI formatına gerek kalmaz. JavaScript ile animasyon veya dinamik renk kontrolü gerekiyorsa inline SVG avantajlıdır (Data URI'deki görsel DOM dışında kalır; CSS fill veya currentColor ile renk değiştirilemez). Dezavantajı: her sayfada tekrar eder, tarayıcı cache'ini kullanamaz, birden fazla bileşen arasında paylaşımı zorlaştırır.

Blob URL ise farklı bir soruyu çözer. URL.createObjectURL() ile oluşturulan geçici URL'ler (blob:https://... formatında), bellekteki binary veriyi tarayıcıya bir kaynak gibi sunar. Tipik kullanım: canvas API ile üretilen görüntü, kullanıcı tarafından seçilen dosyanın önizlemesi, ya da WebSocket üzerinden gelen binary frame. Base64 encode maliyeti yoktur — bellekte sadece bir referans tutulur, string'e çevrim yapılmaz. Sayfa kapandığında URL otomatik olarak geçersiz olur; kalıcı depolama için uygun değildir.

Bu üçünün ortak paydası: tarayıcıya "HTTP isteği yapma, veri burada" demek. Fark, verinin nerede tutulduğu ve yaşam döngüsünün nasıl yönetildiğinde.

Ne zaman kullanmalı, ne zaman kaçınmalı

Data URI en iyi performansı şu durumlarda gösterir:

  • 2KB altındaki küçük ve tekrar eden ikonlar — özellikle SVG veya PNG
  • Kritik yol üzerindeki görsel: sayfanın ilk boyaması için zorunlu, başka türlü ertelenecek bir resim
  • Email HTML — çoğu email istemcisi harici resim isteğini engeller; gömülü resim bu sorunu çözer
  • Dinamik üretilen görseller — sunucu tarafından oluşturulan bir grafik, dosyaya yazılmadan doğrudan embed edilir

Kaçınılacak durumlar:

  • Hero görseller ve büyük ürün fotoğrafları — boyut artışı ve cache bozulması faydadan ağır basar
  • Sık güncellenen görseller — kaynak değiştiğinde tüm HTML veya CSS yeniden derlenir ve dağıtılır
  • Lazy loading gerektiren içerik — Data URI'yi gecikmeli yüklemek pratik değil; resim sayfa yüklendiğinde zaten bellekte
  • SEO kritik görseller — arama motorlarının Data URI görsellerini harici dosyalar kadar güvenilir işlediğine dair net bir kaynak yok

Bir de göz ardı edilen kısıtlama: bazı Content Security Policy yapılandırmaları img-src data: iznini açıkça vermez. Bu durumda tarayıcı Data URI'yi sessizce engeller — geliştirme ortamında çalışıp production'da görüntü göstermeyen ikonların sebebi çoğunlukla bu politikadır. CSP başlığına img-src 'self' data: eklemek sorunu çözer; ama bu izni açmak güvenlik politikasını genişletir, dolayısıyla yalnızca gerçekten gerekli durumlarda yapılmalı.

Gömme kararı, encode etmekten daha önemlidir. Küçük ikonları CSS'e gömmek gerçek avantaj sağlar. Büyük bir hero görseli gömmek ise sayfa boyutunu şişirir, cache stratejisini bozar ve kullanıcının aynı resmi her ziyarette yeniden işlemesine yol açar. Resimleri ayrı tutup optimize ederek dağıtmak çoğu durumda daha temiz bir stratejidir.