Bir tuvalde gerçekte kaç piksel vardır?
Chrome 84'ten itibaren ResizeObserver, öğenin boyutunu fiziksel piksel cinsinden ölçen devicePixelContentBox
adlı yeni bir kutu ölçümünü destekler. Bu, özellikle yüksek yoğunluklu ekranlar bağlamında piksel mükemmelliğinde grafiklerin oluşturulmasını sağlar.
Tarayıcı Desteği
- 84
- 84
- 93
- x
Arka plan: CSS pikselleri, tuval pikselleri ve fiziksel pikseller
Genellikle em
, %
veya vh
gibi uzunluklu soyut birimlerle çalışsak da tüm bu işlerin tümü piksellere denk gelir. CSS'de bir öğenin boyutunu veya konumunu belirttiğimizde, tarayıcının düzen motoru sonuçta bu değeri piksele (px
) dönüştürür. Bunlar, çok sayıda geçmişi olan ve ekranınızdaki piksellerle yalnızca serbest bir ilişkisi olan "CSS Pikselleri"dir.
Uzun bir süre için, bir kişinin ekran piksel yoğunluğunu 96 DPI ("inç başına nokta sayısı") ile tahmin etmek oldukça makul bir ölçüttür. Diğer bir deyişle, herhangi bir monitörün cm başına yaklaşık 38 piksel olması gerekir. Zaman içinde, monitörler büyümüş ve/veya küçülmeye ya da aynı yüzey alanında daha fazla piksele sahip olmaya başlamıştır. Bu durumu, px
yazı tipi boyutu da dahil olmak üzere web'deki pek çok içeriğin boyutlarının tanımlandığı ve bu yüksek yoğunluklu ("HiDPI") ekranlarda okunaksız metinlerle karşılaştığımız gerçeği de hesaba katarız. Buna karşı bir önlem olarak tarayıcılar ekranın gerçek piksel yoğunluğunu gizler ve bunun yerine kullanıcının ekranı 96 DPI olduğunu varsayar. CSS'deki px
birimi, 96 DPI sanal ekranda bir pikselin boyutunu temsil eder. Bu nedenle "CSS Pikseli" adı verilir. Bu birim yalnızca ölçüm ve konumlandırma için kullanılır. Gerçek oluşturma gerçekleşmeden önce, fiziksel piksellere dönüşüm gerçekleşir.
Bu sanal ekrandan kullanıcının gerçek ekranına nasıl geçebiliriz? Şunu girin: devicePixelRatio
Bu genel değer, tek bir CSS pikseli oluşturmak için kaç fiziksel piksele ihtiyacınız olduğunu belirtir. devicePixelRatio
(dPR) değeri 1
ise yaklaşık 96 DPI'ya sahip bir monitörle çalışıyorsunuz demektir. Retina ekranınız varsa dPR'niz muhtemelen 2
olur. Telefonlarda 2
, 3
, hatta 2.65
gibi daha yüksek (ve daha tuhaf) dPR değerleriyle karşılaşmak olağan dışı bir durumdur. Bu değerin tam olduğunu unutmamak gerekir, ancak monitörün gerçek DPI değerini elde etmenize izin vermez. 2
dPR'si, 1 CSS pikselinin tam olarak 2 fiziksel pikselle eşleneceği anlamına gelir.
1
Ekran genişliği 3.440 piksel, görüntüleme alanı ise 79 cm genişliğinde.
Böylece 110 DPI çözünürlük elde edilir. 96'ya yakın ama doğru değil.
<div style="width: 1cm; height: 1cm">
cihazının çoğu ekranda tam olarak 1 cm ölçülmemesinin nedeni de budur.
Son olarak, dPR, tarayıcınızın yakınlaştırma özelliğinden de etkilenebilir. Yakınlaştırırsanız tarayıcı bildirilen dPR'yi artırarak her şeyin daha büyük olmasına neden olur. Yakınlaştırırken Geliştirici Araçları Konsolu'nda devicePixelRatio
kutusunu işaretlerseniz kesirli değerler görebilirsiniz.
<canvas>
öğesini karışıma ekleyelim. width
ve height
özelliklerini kullanarak kanvasın kaç piksele sahip olmasını istediğinizi belirtebilirsiniz. <canvas width=40 height=30>
, 40x30 piksellik bir tuval olur. Ancak bu, reklamın 40x30 piksel boyutunda gösterileceği anlamına gelmez. Varsayılan olarak, kanvas, içsel boyutunu tanımlamak için width
ve height
özelliklerini kullanır. Ancak bildiğiniz ve sevdiğiniz tüm CSS özelliklerini kullanarak kanvası dilediğiniz şekilde yeniden boyutlandırabilirsiniz. Şu ana kadar öğrendiklerimizi dikkate alarak, bunun her senaryo için ideal olmayabileceğini düşünebilirsiniz. Kanvastaki bir piksel, birden çok fiziksel pikseli veya bir fiziksel pikselin yalnızca bir kısmını kaplayabilir. Bu da hoş olmayan görsel yapılara yol açabilir.
Özetlemek gerekirse: Tuval öğeleri, üzerinde çizim yapabileceğiniz alanı tanımlamak için belirli bir boyuta sahiptir. Kanvas piksellerinin sayısı, CSS pikseli olarak belirtilen kanvasın ekran boyutundan tamamen bağımsızdır. CSS pikseli sayısı, fiziksel piksel sayısı ile aynı değildir.
Pixel mükemmelliği
Bazı senaryolarda, tuval piksellerinden fiziksel piksellere tam bir eşlemenin olması istenir. Bu eşleme gerçekleştirilirse, bu "piksel-mükemmel" olarak adlandırılır. Piksel mükemmelliği oluşturma, özellikle alt piksel oluşturma kullanılırken veya grafiklerin dönüşümlü parlaklıkta iyi bir şekilde hizalı satırlarıyla görüntülendiği durumlarda metnin okunabilir şekilde oluşturulması için büyük önem taşır.
Web'de mükemmel piksel kalitesine sahip bir tuvale olabildiğince yakın bir sonuç elde etmek için en çok tercih edilen yaklaşım bu oldu:
<style>
/* … styles that affect the canvas' size … */
</style>
<canvas id="myCanvas"></canvas>
<script>
const cvs = document.querySelector('#myCanvas');
// Get the canvas' size in CSS pixels
const rectangle = cvs.getBoundingClientRect();
// Convert it to real pixels. Ish.
cvs.width = rectangle.width * devicePixelRatio;
cvs.height = rectangle.height * devicePixelRatio;
// Start drawing…
</script>
Akıllı okuyucu, dPR tam sayı değeri olmadığında ne olacağını merak ediyor olabilir. Bu güzel bir soru ve tüm bu sorunun en önemli noktasının tam olarak ne olduğu merak ediliyor. Ayrıca bir öğenin konumunu veya boyutunu yüzde, vh
ya da diğer dolaylı değerleri kullanarak belirtirseniz bunların CSS piksel değerlerine çözümlenmesi mümkündür. margin-left: 33%
değerine sahip bir öğe, şunun gibi bir dikdörtgene sahip olabilir:
CSS pikselleri tamamen sanaldır, dolayısıyla teoride pikselin kesirli olması uygundur, ancak tarayıcı fiziksel piksellerle eşlemeyi nasıl çözer? Çünkü kesirli fiziksel pikseller bir şey değildir.
Piksel tutturma
Birim dönüştürme işleminin, öğelerin fiziksel piksellerle hizalanmasını sağlayan kısmına "piksel tutturma" adı verilir ve kutu üzerinde yaptığı işlem yapılır: Kesirli piksel değerlerini tam sayı, fiziksel piksel değerlerine tutturur. Bunun tam olarak nasıl gerçekleştiği tarayıcıdan tarayıcıya farklılık gösterir. dPR'nin 1 olduğu bir ekranda 791.984px
genişliğinde bir öğemiz varsa bir tarayıcı bu öğeyi 792px
fiziksel pikselde, başka bir tarayıcı ise 791px
değerinde oluşturabilir. Bu durumda sadece tek bir piksel eksik, ancak tek bir piksel mükemmel piksel
olması gereken oluşturmalar için zararlı olabilir. Bu durum, bulanıklığa veya Moiré efekti gibi daha görünür kusurlara neden olabilir.
devicePixelContentBox
devicePixelContentBox
, bir öğenin içerik kutusunu cihaz pikseli (yani fiziksel piksel) birimlerinde verir. Bu, ResizeObserver
kapsamında. Safari 13.1'den bu yana DimensionObserver tüm önemli tarayıcılarda desteklenmektedir. Bununla birlikte, devicePixelContentBox
özelliği şimdilik yalnızca Chrome 84 ve sonraki sürümlerde kullanılmaktadır.
ResizeObserver
bölümünde belirtildiği gibi: Öğeler için document.onresize
işlevine benzerdir. ResizeObserver
öğesinin geri çağırma işlevi, boyama öncesinde ve düzenden sonra çağrılacaktır. Bu, geri çağırmaya ilişkin entries
parametresinin, gözlemlenen tüm öğelerin boyutlarını boyanmadan hemen önce içereceği anlamına gelir. Yukarıda özetlenen tuval sorunumuz bağlamında, bu fırsatı tuvalimizdeki piksel sayısını ayarlamak için kullanabiliriz. Böylece, tuval pikselleri ile fiziksel pikseller arasında tam bire bir eşleme yapabiliyoruz.
const observer = new ResizeObserver((entries) => {
const entry = entries.find((entry) => entry.target === canvas);
canvas.width = entry.devicePixelContentBoxSize[0].inlineSize;
canvas.height = entry.devicePixelContentBoxSize[0].blockSize;
/* … render to canvas … */
});
observer.observe(canvas, {box: ['device-pixel-content-box']});
observer.observe()
için seçenekler nesnesindeki box
özelliği, gözlemlemek istediğiniz boyutları tanımlamanıza olanak tanır. Dolayısıyla her ResizeObserverEntry
her zaman borderBoxSize
, contentBoxSize
ve devicePixelContentBoxSize
sağlar (tarayıcının desteklemesi koşuluyla) geri çağırma yalnızca gözlemlenen kutu metriklerinden herhangi biri değişirse çağrılır.
Bu yeni özellik sayesinde kanvasımızın boyutunu ve konumunu bile canlandırabilir (kesirli piksel değerlerini etkili bir şekilde garanti eder) ve oluşturma üzerinde Moiré etkisi görmeyebiliriz. Moiré'nin getBoundingClientRect()
kullanarak yaklaşım üzerindeki etkisini ve yeni ResizeObserver
özelliğinin bunu önlemenize nasıl olanak tanıdığını görmek isterseniz Chrome 84 veya sonraki sürümlerdeki demoya göz atın.
Özellik algılama
Bir kullanıcının tarayıcısının devicePixelContentBox
desteği olup olmadığını kontrol etmek için herhangi bir öğeyi gözlemleyip özelliğin ResizeObserverEntry
üzerinde mevcut olup olmadığını kontrol edebiliriz:
function hasDevicePixelContentBox() {
return new Promise((resolve) => {
const ro = new ResizeObserver((entries) => {
resolve(entries.every((entry) => 'devicePixelContentBoxSize' in entry));
ro.disconnect();
});
ro.observe(document.body, {box: ['device-pixel-content-box']});
}).catch(() => false);
}
if (!(await hasDevicePixelContentBox())) {
// The browser does NOT support devicePixelContentBox
}
Sonuç
Pikseller web'de şaşırtıcı derecede karmaşık bir konudur ve şimdiye kadar bir öğenin kullanıcının ekranında kapladığı fiziksel piksel sayısını tam olarak bilmenin bir yolu yoktu. ResizeObserverEntry
üzerindeki yeni devicePixelContentBox
özelliği, bu bilgiyi verir ve <canvas>
ile mükemmel piksel oluşturmalar yapmanızı sağlar. devicePixelContentBox
, Chrome 84 ve sonraki sürümlerde desteklenir.