Değişken piksel yoğunlukları için yüksek DPI resimler

Boris Smus
Boris Smus

Yayınlanma tarihi: 22 Ağustos 2012, Son güncelleme tarihi: 14 Nisan 2025

Piyasada çok sayıda cihaz bulunduğundan çok çeşitli ekran piksel yoğunlukları mevcuttur. Uygulama geliştiricilerin bir dizi piksel yoğunluğunu desteklemesi gerekir. Bu, oldukça zor olabilir. Mobil web'de zorluklar çeşitli faktörlerle daha da artar:

  • Farklı form faktörlerine sahip çok çeşitli cihazlar.
  • Ağ bant genişliği ve pil ömrü sınırlıdır.

Web geliştiricilerinin resimlerle ilgili hedefi, mümkün olan en yüksek kaliteli resimleri mümkün olduğunca verimli bir şekilde sunmaktır. Burada, bunu şimdi ve gelecekte yapmak için kullanabileceğiniz bazı faydalı tekniklerden bahsedeceğiz.

Mümkün olduğunda resimlerden kaçının

Resim eklemeniz gerektiğini varsaymadan önce, web'de çözünürlük ve DPI'den bağımsız çok sayıda güçlü teknoloji olduğunu unutmayın. Özellikle metin, SVG ve CSS'nin büyük bir kısmı, devicePixelRatio ile web'in otomatik piksel ölçeklendirme özelliği sayesinde "kolayca çalışır".

Bununla birlikte, raster resimlerden her zaman kaçınamazsınız. Örneğin, saf SVG'lerde veya CSS'de kopyalanması oldukça zor öğeler alabilirsiniz. Fotoğrafla uğraşıyor olabilirsiniz. Bir resmi otomatik olarak SVG'ye dönüştürebilirsiniz ancak fotoğrafları vektörleştirmek pek mantıklı değildir çünkü ölçeklendirilmiş sürümler genellikle iyi görünmez.

Piksel yoğunluğunun geçmişi

İlk zamanlarda bilgisayar ekranlarının piksel yoğunluğu 72 veya 96 inç başına nokta (DPI) idi.

Ekranların piksel yoğunluğu, büyük ölçüde mobil cihazların gelişimiyle birlikte kademeli olarak iyileşti. Kullanıcılar genellikle telefonlarını yüzlerine daha yakın tuttuklarından pikseller daha görünür hale geldi. 2008'e gelindiğinde 150 dpi telefonlar yeni norm haline geldi. Ekran yoğunluğundaki artış devam etti ve günümüz telefonlarında 300 dpi ekranlar bulunuyor.

Pratikte, düşük yoğunluklu resimler yeni ekranlarda eski ekranlarda olduğu gibi görünmelidir. Ancak kullanıcıların görmeye alıştığı yüksek yoğunluklu net görüntülere kıyasla düşük yoğunluklu resimler rahatsız edici ve piksel piksel görünür. Aşağıda, 1x boyuttaki bir resmin 2x ekranda nasıl görüneceğinin kabaca bir simülasyonu verilmiştir. Buna karşılık, 2x resim oldukça iyi görünüyor.

1x piksel 2x piksel
Baboon 1x piksel yoğunluğu. Baboon 2x piksel yoğunluğu.
Farklı piksel yoğunluklarındaki babunlar.

Web'deki pikseller

Web tasarlanırken ekranların% 99'u 96 dpi idi ve varyasyonlar için çok az düzenleme yapılmıştı. Ekran boyutları ve yoğunluklarında büyük bir çeşitlilik olduğu için resimlerin tüm ekranlarda iyi görünmesini sağlayacak standart bir yönteme ihtiyacımız var.

HTML spesifikasyonu, üreticilerin CSS pikselinin boyutunu belirlemek için kullandığı bir referans piksel tanımlayarak bu sorunu çözdü.

Referans pikseli kullanarak üreticiler, cihazın fiziksel pikseli boyutunu standart veya ideal piksele göre belirleyebilir. Bu orana cihaz piksel oranı denir.

Cihaz piksel oranını hesaplama

Bir cep telefonunun fiziksel piksel boyutu inç başına 180 piksel (ppi) olan bir ekrana sahip olduğunu varsayalım. Cihaz piksel oranını hesaplamak için üç adım gerekir:

  1. Cihazın tutulduğu gerçek mesafeyi referans pikselin mesafesiyle karşılaştırın.

    Spesifikasyona göre, 28 inç için ideal inç başına 96 pikseldir. Kullanıcıların yüzlerinin, dizüstü ve masaüstü bilgisayarlara kıyasla mobil cihazlara daha yakın olduğunu biliyoruz. Aşağıdaki denklemlerde bu mesafenin 45 cm olduğunu varsayıyoruz.

  2. Belirtilen mesafe için ideal piksel yoğunluğunu elde etmek üzere mesafe oranını standart yoğunlukla (96 ppi) çarpın.

    idealPixelDensity = (28/18) * 96 = inç başına 150 piksel (yaklaşık)

  3. Cihaz piksel oranını bulmak için fiziksel piksel yoğunluğunun ideal piksel yoğunluğuna oranını alın.

    devicePixelRatio = 180/150 = 1,2

Cihaz piksel oranının nasıl hesaplandığını gösteren bir referans açısal piksel.

Bu nedenle, bir tarayıcı ideal veya standart çözünürlüğe göre bir resmi ekrana sığacak şekilde nasıl yeniden boyutlandıracağını bildiğinde 1, 2 cihaz piksel oranını referans alır. Diğer bir deyişle, bu cihazda her ideal piksel için 1,2 fiziksel piksel bulunur. İdeal (web spesifikasyonu tarafından tanımlandığı şekilde) ve fiziksel (cihaz ekranındaki noktalar) piksel arasında geçiş yapmak için kullanılan formül şudur:

physicalPixels = window.devicePixelRatio * idealPixels

Geçmişte cihaz tedarikçileri devicePixelRatios değerini (DPR'ler) yuvarlama eğilimindeydi. Apple'ın iPhone ve iPad'leri 1 DPR, Retina eşdeğerlerininki ise 2 DPR olarak raporlanır. CSS spesifikasyonu,

piksel birimi, referans piksele en yakın cihaz pikseli tam sayısını ifade eder.

Yuvarlak oranların daha iyi olmasının bir nedeni, daha az alt piksel yapılarına yol açmalarıdır.

Ancak cihaz ortamının gerçekliği çok daha çeşitlidir ve Android telefonların DPR'si genellikle 1,5'tir. Nexus 7 tabletin DPR'si yaklaşık 1,33'tür.Bu değere, önceki örneğe benzer bir hesaplama yapılarak ulaşılmıştır. Gelecekte değişken DPR'lere sahip daha fazla cihaz göreceksiniz. Bu nedenle, müşterilerinizin tam sayı DPR'lerine sahip olduğunu asla varsaymayın.

HiDPI resim teknikleri

En yüksek kaliteli resimleri olabildiğince hızlı bir şekilde gösterme sorununu çözmek için birçok teknik vardır. Bu teknikler genel olarak iki kategoriye ayrılır:

  1. Tek resimleri optimize etme
  2. Birden fazla resim arasından seçim yapmayı optimize etme.

Tek resimli yaklaşımlar: Tek bir resim kullanın ancak bu resimle akıllıca bir şey yapın. Bu yaklaşımların dezavantajı, daha düşük DPI'ye sahip eski cihazlarda bile HiDPI resimler indirmeniz gerektiğinden performanstan ödün vermeniz gerektiğidir. Tek resimli durum için bazı yaklaşımlar şunlardır:

  • Çok sıkıştırılmış HiDPI resim
  • Süper resim biçimi
  • Progresif resim biçimi

Birden fazla resim yaklaşımı: Birden fazla resim kullanın ancak hangilerinin yükleneceğini seçmek için akıllıca bir şey yapın. Bu yaklaşımlar, geliştiricinin aynı öğenin birden fazla sürümünü oluşturması ve ardından bir karar stratejisi belirlemesi için doğal olarak ek maliyetler içerir. Seçenekleri aşağıda bulabilirsiniz:

  • JavaScript
  • Sunucu tarafı yayınlama
  • CSS medya sorguları
  • Dahili tarayıcı özellikleri (image-set(), <img srcset>)

Çok sıkıştırılmış HiDPI resim

Görseller, ortalama bir web sitesini indirmek için harcanan bant genişliğinin% 60'ını oluşturuyor. Tüm istemcilere HiDPI resimler sunarak bu sayıyı artırırız. Ne kadar büyüyebilir?

90, 50 ve 20 JPEG kalitesinde 1x ve 2x resim parçaları oluşturan bazı testler çalıştırdım.

Sıkıştırma ve piksel yoğunluğu açısından farklı olan bir resmin altı sürümü. Sıkıştırma ve piksel yoğunluğu açısından farklı olan bir resmin altı sürümü. Sıkıştırma ve piksel yoğunluğu açısından farklı olan bir resmin altı sürümü.

Bu küçük ve bilimsel olmayan örneklemede, büyük resimlerin sıkıştırılmasının kalite-boyut dengesi açısından iyi bir tercih olduğu görülüyor. Bence, çok sıkıştırılmış 2x görüntüler, sıkıştırılmamış 1x resimlerden daha iyi görünüyor.

Bununla birlikte, 2x cihazlara düşük kaliteli, yüksek sıkıştırılmış 2x görüntüler yayınlamak daha yüksek kaliteli görüntüler yayınlamaktan daha kötüdür ve bu yaklaşım görüntü kalitesi cezalarına neden olur. quality: 90 resimlerini quality: 20 resimleriyle karşılaştırırsanız resmin netliği azalır ve resimde taneciklenme artar. Yüksek kaliteli resimlerin önemli olduğu yerlerde (ör. fotoğraf görüntüleyici uygulaması) veya ödün vermek istemeyen uygulama geliştiriciler için quality:20 içeren yapıların kabul edilmesi uygun olmayabilir.

Bu karşılaştırma tamamen sıkıştırılmış JPEG'lerle yapılmıştır. Yaygın olarak kullanılan resim biçimleri (JPEG, PNG, GIF) arasında birçok değiş tokuş olduğunu belirtmek isteriz. Bu da bizi şu noktaya getiriyor:

WebP: Muhteşem bir resim biçimi

WebP, yüksek resim doğruluğunu korurken çok iyi sıkıştıran oldukça etkileyici bir resim biçimidir.

WebP desteğini kontrol etmenin bir yolu JavaScript'i kullanmaktır. data-uri ile 1 piksellik bir resim yükleyin, loaded veya error etkinliklerinin tetiklenmesini bekleyin ve ardından boyutun doğru olduğunu doğrulayın. Modernizr, Modernizr.webp ile kullanılabilen böyle bir özellik algılama komut dosyasıyla birlikte gönderilir.

Ancak bunu yapmanın daha iyi bir yolu, doğrudan CSS'de image() işlevini kullanmaktır. Dolayısıyla, WebP resminiz ve JPEG yedeğiniz varsa aşağıdakileri yazabilirsiniz:

#pic {
  background: image("foo.webp", "foo.jpg");
}

Bu yaklaşımın birkaç sorunu vardır. İlk olarak, image() henüz yaygın olarak uygulanmıyor. İkinci olarak, WebP sıkıştırması JPEG'i geride bıraksa da nispeten kademeli bir iyileştirmedir. Bu WebP galerisine göre yaklaşık% 30 daha küçüktür. Bu nedenle, yüksek DPI sorununu çözmek için yalnızca WebP yeterli değildir.

Progresif resim biçimleri

JPEG 2000, Progressive JPEG, Progressive PNG ve GIF gibi aşamalı resim biçimlerinin, resmin tamamen yüklenmeden önce yerine gelmesini görme avantajı vardır (biraz tartışmalıdır). Bu konuda çelişkili kanıtlar olsa da bazı boyut ek maliyetleri olabilir. Jeff Atwood, aşamalı modun "PNG resimlerinin boyutuna yaklaşık% 20, JPEG ve GIF resimlerinin boyutuna ise yaklaşık% 10 eklediğini iddia etti". Ancak Stoyan Stefanov, büyük dosyalar için aşamalı modun (çoğu durumda) daha verimli olduğunu iddia ediyor.

İlk bakışta, en yüksek kaliteli resimleri olabildiğince hızlı bir şekilde sunma bağlamında aşamalı resimler çok umut verici görünüyor. Buradaki amaç, ek verilerin görüntü kalitesini artırmayacağını anladığında tarayıcının görüntünün indirilmesini ve kodunu çözmesini durdurabilmesidir (ör. tüm doğruluk iyileştirmeleri alt pikseldir).

Bağlantıların sonlandırılması hızlı olsa da yeniden başlatılması genellikle pahalıdır. Çok sayıda resmi olan bir site için en verimli yaklaşım, tek bir HTTP bağlantısını mümkün olduğunca uzun süre boyunca yeniden kullanarak etkin durumda tutmaktır. Bir resim yeterince indirildiği için bağlantı erken sonlandırılırsa tarayıcının yeni bir bağlantı oluşturması gerekir. Bu işlem, düşük gecikmeli ortamlarda çok yavaş olabilir.

Bununla ilgili bir geçici çözüm, tarayıcıların getirilecek bir bayt aralığı belirtmesine olanak tanıyan HTTP Aralığı isteğini kullanmaktır. Akıllı bir tarayıcı, başlığa ulaşmak, başlığı işlemek, resmin ne kadarının gerçekten gerekli olduğuna karar vermek ve ardından resmi getirmek için bir HEAD isteği gönderebilir. Maalesef HTTP aralığı, web sunucularında yeterince desteklenmediğinden bu yaklaşım pratik değildir.

Son olarak, bu yaklaşımın bariz bir sınırlaması, hangi resmin yükleneceğini seçememenizdir. Yalnızca aynı resmin farklı çözünürlüklerini seçebilirsiniz. Bu nedenle, "sanat yönetmenliği" kullanım alanı bu kapsamda değildir.

Hangi resmin yükleneceğine karar vermek için JavaScript kullanma

Hangi resmin yükleneceğine karar vermek için ilk ve en belirgin yaklaşım, istemcide JavaScript kullanmaktır. Bu yaklaşım, kullanıcı aracınız hakkında her şeyi öğrenmenize ve doğru şeyi yapmanıza olanak tanır. window.devicePixelRatio ile cihaz piksel oranını belirleyebilir, ekran genişliğini ve yüksekliğini alabilir, hatta navigator.connection ile ağ bağlantısı taraması yapabilir veya foresight.js kitaplığının yaptığı gibi sahte istek gönderebilirsiniz. Tüm bu bilgileri topladıktan sonra hangi resmin yükleneceğine karar verebilirsiniz.

Bu tekniği kullanan yaklaşık bir milyon JavaScript kitaplığı vardır. Maalesef bunların hiçbiri özellikle öne çıkmıyor.

En büyük dezavantaj, önizleme ayrıştırıcısı bitene kadar resim yüklemeyi geciktirmenizdir. Bu, temel olarak resimlerin pageload etkinliği tetiklenene kadar indirilmeye bile başlamayacağı anlamına gelir. Bu konu hakkında daha fazla bilgiyi Jason Grigsby'nin makalesinde bulabilirsiniz.

Sunucuya hangi resmin yükleneceğine karar verme

Sunduğunuz her resim için özel istek işleyicileri yazarak kararı sunucu tarafına bırakabilirsiniz. Bu tür bir işleyici, kullanıcı aracısına (sunucuyla paylaşılan tek bilgi) göre Retina desteğini kontrol eder. Ardından, sunucu tarafı mantığının HiDPI öğeleri sunup sunmayacağına bağlı olarak uygun öğeyi (bilinen bir adlandırma kuralına göre adlandırılmış) yüklersiniz.

Maalesef User-Agent, bir cihazın yüksek mi yoksa düşük kaliteli mi resim alması gerektiğine karar vermek için her zaman yeterli bilgi sağlamaz. Ayrıca, stil kararları almak için User-Agent kullanan çözümlerden kaçınılmalıdır.

CSS medya sorgularını kullanma

CSS medya sorguları, beyan niteliğinde olduğundan amacınızı belirtmenize ve tarayıcının sizin adınıza doğru şeyi yapmasına olanak tanır. Medya sorgularının en yaygın kullanımı olan cihaz boyutunu eşlemeye ek olarak devicePixelRatio ile de eşleyebilirsiniz. İlişkili medya sorgusu device-pixel-ratio'dur ve tahmin edebileceğiniz gibi minimum ve maksimum varyantları vardır.

Yüksek DPI resimler yüklemek istiyorsanız ve cihaz piksel oranı bir eşiği aşıyorsa aşağıdakileri yapabilirsiniz:

#my-image { background: (low.png); }

@media only screen and (min-device-pixel-ratio: 1.5) {
  #my-image { background: (high.png); }
}

Tüm tedarikçi firma ön eklerinin karıştırılması, özellikle de "min" ve "max" ön eklerinin yerleşimindeki büyük farklılıklar nedeniyle biraz daha karmaşık hale gelir:

@media only screen and (min--moz-device-pixel-ratio: 1.5),
    (-o-min-device-pixel-ratio: 3/2),
    (-webkit-min-device-pixel-ratio: 1.5),
    (min-device-pixel-ratio: 1.5) {

  #my-image {
    background:url(high.png);
  }
}

Bu yaklaşımla, JavaScript çözümünde kaybedilen ileriye dönük ayrıştırmanın avantajlarından yeniden yararlanabilirsiniz. Ayrıca, duyarlı durma noktalarınızı seçme esnekliğine de sahip olursunuz (ör. düşük, orta ve yüksek DPI resimleriniz olabilir). Bu esneklik, sunucu tarafı yaklaşımında yoktu.

Maalesef bu yöntem hâlâ biraz hantal ve garip görünümlü CSS'lere yol açıyor ya da ön işlem gerektiriyor. Ayrıca bu yaklaşım CSS mülkleriyle sınırlıdır. Bu nedenle, <img src> ayarlamak mümkün değildir ve resimlerinizin tümü arka planı olan öğeler olmalıdır. Son olarak, yalnızca cihaz piksel oranına güvenerek yüksek DPI'li cep telefonunuzun EDGE bağlantısı kullanırken büyük bir 2x resim öğesi indirdiği durumlarla karşılaşabilirsiniz. Bu, en iyi kullanıcı deneyimi değildir.

image-set() bir CSS işlevi olduğundan <img> etiketleriyle ilgili sorunu gidermez. Bu sorunu gideren @srcset öğesini girin. Sonraki bölümde image-set ve srcset hakkında daha fazla bilgi verilmektedir.

Yüksek DPI desteği için tarayıcı özellikleri

Yüksek DPI desteğine nasıl yaklaşacağınız, ihtiyaçlarınıza bağlıdır. Yukarıda belirtilen yaklaşımların hepsinin dezavantajları vardır.

image-set ve srcset yaygın olarak desteklendikleri için en iyi çözümlerdir. Eski tarayıcılarda daha iyi sonuçlar elde etmemizi sağlayabilecek ek en iyi uygulamalar da vardır.

Bu iki seçenek arasındaki fark nedir? image-set(), arka plan CSS özelliğinin değeri olarak kullanılması uygun olan bir CSS işlevidir. srcset, benzer söz dizimine sahip <img> öğelerine özgü bir özelliktir. Bu etiketlerin her ikisi de resim beyanları belirtmenize olanak tanır ancak srcset özelliği, görüntü boyutuna göre hangi resmin yükleneceğini de yapılandırmanıza olanak tanır.

Resim grubuyla ilgili en iyi uygulamalar

image-set() söz dizimi, bir URL dizesi veya url() işlevinin ardından uygun çözünürlüğün yer aldığı, virgülle ayrılmış bir veya daha fazla resim beyanı alır. Örneğin:

image-set(
  url("image1.jpg") 1x,
  url("image2.jpg") 2x
);

/* You can also include image-set without `url()` */
image-set(
  "image1.jpg" 1x,
  "image2.jpg" 2x
);

Bu, tarayıcıya aralarından seçim yapılabilecek iki resim olduğunu bildirir. Bir resim 1x ekranlar, diğeri ise 2x ekranlar için optimize edilmiştir. Ardından tarayıcı, çeşitli faktörlere göre hangisinin yükleneceğini seçer. Tarayıcının yeterince akıllı olması durumunda ağ hızı da bu faktörler arasında yer alabilir.

Tarayıcı, doğru resmi yüklemenin yanı sıra resmi uygun şekilde ölçeklendirir. Diğer bir deyişle tarayıcı, 2x resimlerin 1x resimlerin iki katı kadar büyük olduğunu varsayar ve bu nedenle, resmin sayfadaki boyutu aynı kalacak şekilde 2x resmi 2 faktörüyle küçültür.

1x, 1, 5x veya Nx yerine DPI cinsinden belirli bir cihaz piksel yoğunluğunu da belirtebilirsiniz.

image-set mülkünü desteklemeyen eski tarayıcılarla ilgili endişeleriniz varsa bir resmin gösterilmesini sağlamak için yedek ekleyebilirsiniz. Örneğin:

/* Fallback support. */
background-image: url(icon1x.jpg);
background-image: image-set(
  url(icon1x.jpg) 1x,
  url(icon2x.jpg) 2x
);

image-set(
  url(icon1x.jpg) 1x,
  url(icon2x.jpg) 2x
);

Bu örnek kod, image-set öğesini destekleyen tarayıcılarda uygun öğeyi yükler ve aksi takdirde 1x öğesine geri döner.

Bu noktada, neden image-set() için polyfill (yani JavaScript shim oluşturma) yapmayıp işimi bitirmediğimi merak ediyor olabilirsiniz. CSS işlevleri için etkili çoklu dolguların uygulanmasının oldukça zor olduğu ortaya çıktı. (Nedeni hakkında ayrıntılı bilgi için bu www-style tartışmasına göz atın).

Resim srcset

image-set öğesinin sağladığı bildirimlerin yanı sıra srcset öğesi, en alakalı sürümü sunmaya çalışarak görüntü alanının boyutuna karşılık gelen genişlik ve yükseklik değerlerini de alır.

<img alt="my awesome image"
  src="banner.jpeg"
  srcset="banner-HD.jpeg 2x, banner-phone.jpeg 640w, banner-phone-HD.jpeg 640w 2x">

Bu örnekte, görüntü alanı genişliği 640 pikselin altında olan cihazlara banner-phone.jpeg, küçük ekranlı yüksek DPI cihazlara banner-phone-HD.jpeg, ekranı 640 pikselden büyük olan yüksek DPI cihazlara banner-HD.jpeg ve diğer tüm cihazlara banner.jpeg sunulur.

Resim öğeleri için image-set öğesini kullanma

img öğelerinizi arka planları olan <div> öğeleriyle değiştirmek ve resim grubu yaklaşımını kullanmak cazip gelebilir. Bu yöntem, bazı sınırlamalarla kullanılabilir. Bunun dezavantajı, <img> etiketinin uzun süreli anlamsal değere sahip olmasıdır. Bu durum, erişilebilirlik ve web tarayıcıları açısından önemlidir.

Resmi devicePixelRation'ye göre otomatik olarak ölçeklendiren content CSS özelliğini kullanabilirsiniz. Örneğin:

<div id="my-content-image"
  style="content: -webkit-image-set(
    url(icon1x.jpg) 1x,
    url(icon2x.jpg) 2x);">
</div>

Polyfill srcset

srcset'ün kullanışlı özelliklerinden biri, doğal bir yedek seçeneği sunmasıdır. srcset özelliğinin uygulanmadığı durumlarda tüm tarayıcılar src özelliğini işlemeyi bilir. Ayrıca, yalnızca bir HTML özelliği olduğundan JavaScript ile polyfill oluşturabilirsiniz.

Bu polyfill, spesifikasyona mümkün olduğunca yakın olmasını sağlamak için birim testleriyle birlikte gelir. Ayrıca, srcset doğal olarak uygulanırsa polyfill'in herhangi bir kod yürütmesini engelleyen kontroller vardır.

Sonuç

Yüksek DPI'li resimler için en iyi çözüm SVG'leri ve CSS'yi tercih etmektir. Ancak bu, özellikle resim yoğun web siteleri için her zaman gerçekçi bir çözüm değildir.

JavaScript, CSS ve sunucu tarafı çözümlerdeki yaklaşımların güçlü ve zayıf yönleri vardır. En umut verici yaklaşım, image-set ve srcset kullanmaktır.

Özetlemek gerekirse önerilerim şu şekildedir: