Bir tuvalde gerçekten kaç piksel var?
Chrome 84'ten itibaren ResizeObserver, devicePixelContentBox
adlı yeni bir kutu ölçümünü destekler. Bu ölçüm, öğenin boyutunu fiziksel piksellerle ölçer. Bu sayede, özellikle yüksek yoğunluklu ekranlarda piksel açısından mükemmel grafikler oluşturulabilir.
Arka plan: CSS pikselleri, tuval pikselleri ve fiziksel pikseller
Genellikle em
, %
veya vh
gibi soyut uzunluk birimleriyle çalışsak da her şey piksellere bağlıdır. CSS'de bir öğenin boyutunu veya konumunu her belirttiğimizde tarayıcının düzen motoru bu değeri sonunda piksele (px
) dönüştürür. Bunlar, çok geçmişi olan ve ekranınızdaki piksellerle yalnızca gevşek bir ilişkisi olan "CSS pikselleri"dir.
Uzun süre boyunca, herkesin ekran piksel yoğunluğunu 96 DPI ("inç başına nokta sayısı") ile tahmin etmek oldukça makul bir yaklaşımdı. Bu, herhangi bir monitörün kabaca santimetre başına 38 piksele sahip olacağı anlamına geliyordu. Zamanla monitörler büyüdü ve/veya küçüldü ya da aynı yüzey alanında daha fazla piksel olmaya başladı. Buna, web'deki birçok içeriğin yazı boyutları da dahil olmak üzere boyutlarını px
cinsinden tanımladığı gerçeğini de eklediğimizde bu yüksek yoğunluklu ("HiDPI") ekranlarda okunaksız metinler ortaya çıkıyor. Tarayıcılar, karşı önlem olarak monitörün gerçek piksel yoğunluğunu gizler ve bunun yerine kullanıcının 96 DPI ekranı olduğunu varsayar. CSS'deki px
birimi, bu sanal 96 DPI ekranda bir pikselin boyutunu temsil eder. Bu nedenle, "CSS Pikseli" olarak adlandırılır. Bu birim yalnızca ölçüm ve konumlandırma için kullanılır. Gerçek bir oluşturma işlemi gerçekleşmeden önce fiziksel piksellere dönüştürme işlemi yapılır.
Bu sanal ekrandan kullanıcının gerçek ekranına nasıl geçiş yaparız? Şunu girin: devicePixelRatio
Bu genel değer, tek bir CSS pikseli oluşturmak için kaç tane fiziksel piksel gerektiğini gösterir. devicePixelRatio
(dPR) 1
ise yaklaşık 96 DPI'lık bir monitörde çalışıyorsunuz demektir. Retina ekranınız varsa dPR'niz muhtemelen 2
'dır. Telefonlarda 2
, 3
veya hatta 2.65
gibi daha yüksek (ve daha garip) dPR değerleriyle karşılaşmak yaygın bir durumdur. Bu değerin kesin olduğunu ancak monitörün gerçek DPI değerini elde etmenize izin vermediğini unutmayın. 2
dPR, 1 CSS pikselinin tam olarak 2 fiziksel piksele eşleneceği anlamına gelir.
1
.Genişliği 3.440 pikseldir ve ekran alanı 79 cm genişliğindedir.
Bu da 110 DPI çözünürlüğe yol açar. 96'ya yakın ama tam değil.
Bu nedenle, çoğu ekranda <div style="width: 1cm; height: 1cm">
1 cm boyutunda ölçülmez.
Son olarak, dPR tarayıcınızın yakınlaştırma özelliğinden de etkilenebilir. Yakınlaştırdığınızda tarayıcı, bildirilen dPR'yi artırır ve her şeyin daha büyük oluşturulmasına neden olur. Yakınlaştırırken bir DevTools Console'da devicePixelRatio
işaretini koyarsanız kesirli değerlerin göründüğünü görebilirsiniz.

devicePixelRatio
gösteren Geliştirici Araçları.<canvas>
öğesini de ekleyelim. width
ve height
özelliklerini kullanarak tuvalin kaç piksel olmasını istediğinizi belirtebilirsiniz. Bu nedenle <canvas width=40 height=30>
, 40 x 30 piksellik bir tuval olur. Ancak bu, 40 x 30 piksel boyutunda gösterileceği anlamına gelmez. Tuval, varsayılan olarak kendi boyutunu tanımlamak için width
ve height
özelliklerini kullanır ancak tuvali, bildiğiniz ve sevdiğiniz tüm CSS özelliklerini kullanarak rastgele yeniden boyutlandırabilirsiniz. Şimdiye kadar öğrendiklerimizden, bu yöntemin her senaryo için ideal olmayabileceğini anlamış olabilirsiniz. Tuvaldeki bir piksel, birden fazla fiziksel pikseli veya fiziksel pikselin yalnızca bir kısmını kaplayabilir. Bu durum, görsel olarak hoş olmayan eserlere yol açabilir.
Özetlemek gerekirse: Tuval öğeleri, üzerinde çizim yapabileceğiniz alanı tanımlamak için belirli bir boyuta sahiptir. Tuval piksellerinin sayısı, CSS pikselleriyle belirtilen tuvalin görüntüleme boyutundan tamamen bağımsızdır. CSS piksellerinin sayısı, fiziksel piksellerin sayısıyla aynı değildir.
Pixel mükemmelliği
Bazı senaryolarda, tuval piksellerinin fiziksel piksellerle tam olarak eşlenmesi istenir. Bu eşleme gerçekleştirilirse "piksel mükemmelliği" olarak adlandırılır. Metnin okunabilir şekilde oluşturulması için piksel düzeyinde mükemmel oluşturma çok önemlidir. Bu durum, özellikle alt piksel oluşturma kullanılırken veya alternatif parlaklıkta sıkıca hizalanmış çizgiler içeren grafikler görüntülenirken geçerlidir.
Web'de piksel açısından mükemmel bir tuvale olabildiğince yakın bir sonuç elde etmek için şu yaklaşım kullanılmıştır:
<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>
Dikkatli okuyucular, dPR tam sayı değeri olmadığında ne olacağını merak edebilir. Bu iyi bir soru ve tüm bu sorunun asıl kaynağı tam olarak burada yatıyor. Ayrıca, bir öğenin konumunu veya boyutunu yüzde, vh
ya da diğer dolaylı değerleri kullanarak belirtirseniz bu değerler kesirli CSS piksel değerlerine dönüşebilir. margin-left: 33%
içeren bir öğe şu şekilde bir dikdörtgenle sonuçlanabilir:

getBoundingClientRect()
çağrısı sonucunda kesirli piksel değerlerini gösteriyor.CSS pikselleri tamamen sanal olduğundan, teoride pikselin kesirli kısımlarının olması sorun değildir. Ancak tarayıcı, fiziksel piksellerle eşlemeyi nasıl belirler? Çünkü kesirli fiziksel pikseller diye bir şey yoktur.
Piksele tutturma
Birim dönüştürme sürecinin, öğeleri fiziksel piksellerle hizalamayı sağlayan kısmına "piksel yapıştırma" denir. Bu işlem, piksel değerlerini tam sayı olan fiziksel piksel değerlerine yapıştırır. Bu durumun 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 genişliği 791.984px
olan bir öğemiz varsa bir tarayıcı bu öğeyi 792px
fiziksel pikselde, başka bir tarayıcı ise 791px
fiziksel pikselde oluşturabilir. Bu, yalnızca tek bir pikselin eksik olmasıdır ancak tek bir piksel, mükemmel piksel gerektiren oluşturma işlemleri için zararlı olabilir. Bu durum, bulanıklığa veya Moiré efekti gibi daha belirgin yapaylıklara yol açabilir.

(Bu resmi, ölçekleme uygulanmadan görmek için yeni bir sekmede açmanız gerekebilir.)
devicePixelContentBox
devicePixelContentBox
, cihaz pikseli (yani fiziksel piksel) birimlerinde bir öğenin içerik kutusunu verir. ResizeObserver
'nın bir parçasıdır. ResizeObserver, Safari 13.1'den beri tüm büyük tarayıcılarda destekleniyor olsa da devicePixelContentBox
özelliği şu anda yalnızca Chrome 84 ve sonraki sürümlerde kullanılabiliyor.
ResizeObserver
: it's like document.onresize
for elements başlıklı makalede belirtildiği gibi, ResizeObserver
öğesinin geri çağırma işlevi, boyamadan önce ve düzenden sonra çağrılır. Bu durumda, geri çağırma işlevine iletilen entries
parametresi, boyanmadan hemen önce gözlemlenen tüm öğelerin boyutlarını içerir. Yukarıda özetlenen kanvas sorunumuz bağlamında, bu fırsatı kanvasımızdaki piksel sayısını ayarlamak için kullanabiliriz. Böylece, kanvas pikselleri ile fiziksel pikseller arasında bire bir eşleme elde edebiliriz.
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, hangi boyutları gözlemlemek istediğinizi tanımlamanıza olanak tanır. Dolayısıyla her ResizeObserverEntry
her zaman borderBoxSize
, contentBoxSize
ve devicePixelContentBoxSize
değerlerini sağlasa da (tarayıcı desteklediği sürece) geri çağırma yalnızca gözlemlenen kutu metriklerinden herhangi biri değişirse çağrılır.
Bu yeni özellik sayesinde, tuvalimizin boyutunu ve konumunu animasyonla değiştirebiliriz (kesirli piksel değerlerini etkili bir şekilde garanti eder) ve oluşturmada herhangi bir Moiré efekti görmeyiz. getBoundingClientRect()
kullanılarak yapılan yaklaşımda Moiré etkisini ve yeni ResizeObserver
özelliğinin bu etkiden nasıl kaçınmanızı sağladığını görmek istiyorsanız Chrome 84 veya sonraki sürümlerdeki demoya göz atın.
Özellik algılama
Bir kullanıcının tarayıcısında devicePixelContentBox
desteği olup olmadığını kontrol etmek için herhangi bir öğeyi gözlemleyebilir ve özelliğin ResizeObserverEntry
üzerinde bulunup bulunmadığı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 size verir ve <canvas>
ile piksel düzeyinde mükemmel oluşturmalar yapmanıza olanak tanır. devicePixelContentBox
, Chrome 84 ve sonraki sürümlerinde desteklenir.