Βαθμονόμηση με φυσικό χάρακα
Ο φυλλομετρητής δεν ξέρει το πραγματικό μέγεθος της οθόνης. Χρησιμοποίησε έναν αληθινό χάρακα πάνω στο τζάμι και ταίριαξε τον εικονικό χάρακα με τον δικό σου. Μόλις κουμπώσουν, ξέρουμε ακριβώς το DPI.
Δεν έχεις χάρακα; Μπορείς να χρησιμοποιήσεις μια τραπεζική κάρτα, που έχει σταθερό μέγεθος 85.60 × 53.98 mm (πρότυπο ISO ID-1). Στον οριζόντιο χάρακα, φέρε τη μεγάλη πλευρά της (85.60 mm) πάνω στην πορτοκαλί γραμμή. Στον κάθετο, ακούμπησε την κάρτα πάνω στο πορτοκαλί πλαίσιο μέχρι να ταιριάξουν.
Οριζόντιο DPI: —
Κάθετο DPI: —
Effective DPI
Τρεις πυκνότητες, τρία διαφορετικά ερωτήματα
Οριζόντιο DPI
Κάθετο DPI
DPR
Ζουμ pinch (visualViewport)
Πραγματικό μέγεθος
Διαγώνιος
| pixel type | 1 pixel σε | 1 mm σε | ||
|---|---|---|---|---|
| inch | mm | pt | pixel | |
| css pixel | 1 / — | — | — | — |
| logical pixel | = css1 | — | — | — |
| device pixel | 1 / — | — | — | — |
| hardware pixel | = device2 | ? | ? | ? |
1 στο 100% zoom · 2 όταν το σύστημα renderάρει στη native ανάλυση
Ξέρεις την πραγματική (native) ανάλυση της οθόνης σου;
Προαιρετικό. Ο φυλλομετρητής δεν έχει τρόπο να τη μάθει, και με το τρέχον DPR δεν ξεχωρίζει μια αληθινή οθόνη υψηλής πυκνότητας από μια εικόνα που ζωγραφίζεται μεγάλη και μετά σμικρύνεται. Αν τη δηλώσεις, το λύνουμε. Θα τη βρεις στις ρυθμίσεις οθόνης του λειτουργικού.
Συνηθισμένες τιμές:
Το hardware pixel το θεωρούμε ίσο με το device: υποθέτουμε δηλαδή ότι η εικόνα φτάνει στην οθόνη χωρίς ενδιάμεση κλίμακα.
Native ανάλυση panel: — δηλωμένη
Η δήλωση μένει τοπικά στον φυλλομετρητή σου (localStorage) και δεν αποστέλλεται πουθενά.
Ο φυλλομετρητής δεν ξέρει το φυσικό μέγεθος της οθόνης. Με τον χάρακα του δίνεις εσύ αυτή την πληροφορία: όταν οι εικονικές χαρακιές πέσουν πάνω στις αληθινές, ξέρουμε πόσα CSS pixel καλύπτουν 1 πραγματικό εκατοστό. Αυτό το μέγεθος, ας το πούμε p (px/cm), είναι όλη η βάση του υπολογισμού.
Τέσσερα «pixel» που συχνά μπερδεύονται, από το πιο νοητό στο πιο υλικό:
| Όνομα | Τι είναι | Σταθερό; | Το έχουμε; |
|---|---|---|---|
| css pixel | η λογική μονάδα του browser για τη διάταξη | Όχι, αλλάζει με το zoom | ✓1 |
| logical pixel | λογικό pixel του λειτουργικού (point / DIP) | Όχι, αλλάζει με το scaling | ✓ |
| device pixel | η επιφάνεια που renderάρει ο browser (css/logical × DPR) | Όχι, αλλάζει με scaling + zoom | ✓2 |
| hardware pixel | η υλική κουκίδα, η native ανάλυση της οθόνης | Ναι, καρφωμένο στο hardware | ✗3 |
1 css pixel: το μετράς εδώ, με τον χάρακα · 2 device pixel: υπολογισμένο, όχι το ίδιο το panel · 3 hardware pixel: δεν έχουμε πρόσβαση, δεν το μετράμε
Ο browser δεν βλέπει την πραγματική οθόνη όπως είναι. Το φυσικό της μέγεθος (πόσες ίντσες) του είναι εντελώς άγνωστο, ενώ την ανάλυση την ξέρει σε CSS pixel (window.screen), επηρεασμένη από το scaling του λειτουργικού και από το zoom, όχι τα device pixel. Το DPR μας πάει στα device pixel, αλλά μπερδεύει μαζί την πυκνότητα της οθόνης με το zoom.
Επειδή λοιπόν λείπει το φυσικό μέγεθος, το DPI δεν προκύπτει από μόνο του: το μετράμε εμείς με τον χάρακα. Το αποτέλεσμα είναι το effective DPI, η πυκνότητα των device pixel (πόσα ανά ίντσα) πάνω στο τζάμι (ίσο με τα hardware pixel όταν το σύστημα renderάρει στη native ανάλυση, χωρίς ενδιάμεσο scaling), που συχνά διαφέρει από αυτό που «υποθέτει» ο browser (τα προκαθορισμένα 96 ppi* του CSS).
* Το CSS ορίζει σταθερά ότι 1 ίντσα = 96 CSS pixel (άρα 1px = 1/96 ίντσας, 1pt = 1.333px, 1cm ≈ 37.8px). Έτσι, για τους σκοπούς του CSS, ο browser «υποθέτει» ότι κάθε οθόνη είναι 96 ppi, ανεξάρτητα από την πραγματική της πυκνότητα. Αν γράψεις width: 1in, παίρνεις 96 CSS pixel, όχι απαραίτητα μία αληθινή ίντσα πάνω στο τζάμι.
Στην περιοχή «Τρεις πυκνότητες» πιο πάνω, όταν οι τιμές διαφέρουν, μπαίνει ο πειρασμός να διαβάσεις τη μικρότερη ως ταβάνι για παράδειγμα: «CSS ppi 100, άρα ό,τι κι αν κάνει το σύστημα, εγώ 100 βλέπω». Δεν ισχύει. Το CSS ppi δεν είναι πυκνότητα λεπτομέρειας, είναι κλίμακα: το σύστημα συντεταγμένων στο οποίο γράφεται το CSS. Οι κουκκίδες του τζαμιού παραμένουν όσες είναι και χρησιμοποιούνται όλες.
Πάρε για παράδειγμα μια οθόνη 125 ppi με scaling 125% και DPR 2, και πάνω της μια λεπτή γραμμή, border: 1px. Στη λογική διάταξη είναι 1 CSS pixel. Ο φυλλομετρητής τη ζωγραφίζει 2 pixel φαρδιά στην επιφάνεια των 200 ppi. Ο compositor σμικρύνει, και η γραμμή καταλήγει να καλύπτει 1,25 πραγματικά pixel του panel: δεν στρογγυλοποιείται σε ένα χοντρό «κουτί των 100», πέφτει πάνω σε ενάμιση περίπου φυσικό pixel με το ένα άκρο μισοφωτισμένο. Ένα γράμμα 16px παίρνει 20 πραγματικές κουκκίδες ύψος, όχι 16.
Άρα τα δύο ερωτήματα έχουν διαφορετική απάντηση: πόσο μεγάλο φαίνεται κάτι το ορίζει το CSS ppi, πόσο καθαρό είναι το ορίζει η πυκνότητα του panel. Το effective DPI στη μέση δεν φτάνει ποτέ στο μάτι: είναι μια ενδιάμεση επιφάνεια που πετιέται στη σμίκρυνση. Κερδίζεις ομαλές καμπύλες αντί για σκαλοπάτια, και πληρώνεις ένα ελαφρύ θόλωμα, γιατί τα rendered pixel δεν πέφτουν ακέραια πάνω στα φυσικά.
Μία εξαίρεση, και είναι πραγματική: η έτοιμη εικόνα. Κείμενο και vector ζωγραφίζονται από την αρχή στη μεγάλη επιφάνεια, οπότε εκμεταλλεύονται όλη την πυκνότητα του panel. Ένα raster όμως κουβαλάει τη δική του λεπτομέρεια και κανένα scaling δεν την αυξάνει: αν σερβιριστεί στα 100 ppi, στα 100 ppi θα μείνει και τα υπόλοιπα 25 του panel μένουν αχρησιμοποίητα. Εκεί, και μόνο εκεί, το ταβάνι είναι όντως το CSS ppi. Γι' αυτό υπάρχει το srcset με παραλλαγή 2x.
Μία ίντσα = 2.54 cm, και κάθε CSS pixel αντιστοιχεί σε DPR device pixel. Άρα τα device pixel ανά ίντσα (το DPI) είναι:
Με pinch-zoom (touch ή trackpad) προστίθεται κι ο παράγοντας visualViewport.scale· το page-zoom (Ctrl +/−) είναι ήδη μέσα στο DPR:
Το μετράμε ξεχωριστά για τον οριζόντιο και τον κάθετο χάρακα και δείχνουμε τον μέσο όρο:
Στη δική σου μέτρηση: p ≈ — px/cm · DPR — → DPI ≈ — ppi
Ξέροντας πόσα CSS pixel = 1 ίντσα (δηλαδή p × 2.54, το «CSS ppi»), το φυσικό πλάτος βγαίνει διαιρώντας την ανάλυση της οθόνης (σε CSS pixel) με αυτό. Ομοίως το ύψος:
Και η διαγώνιος από το Πυθαγόρειο θεώρημα:
Στη δική σου μέτρηση: w ≈ —″ · h ≈ —″ · D ≈ —″
Προσοχή: το φυσικό μέγεθος και η διαγώνιος ισχύουν για το τρέχον zoom. Το page-zoom του browser (Ctrl +/−) τα μετατοπίζει, γιατί το window.screen.width δεν συμβαδίζει με τη βαθμονόμηση όταν αλλάζει το zoom (και το επίπεδο zoom δεν ανιχνεύεται από τη σελίδα). Για ακριβή τιμή, μέτρα στο 100% zoom — το DPI πάντως μένει σωστό.
Σε οθόνες υψηλής πυκνότητας (retina) ένα CSS pixel δεν είναι ένα device pixel· είναι DPR device (π.χ. 2×2 = 4). Ο χάρακας μετράει σε CSS pixel, οπότε για να φτάσουμε στα device pixel πολλαπλασιάζουμε με το DPR. Χωρίς αυτό, το DPI θα έβγαινε το μισό (το «CSS ppi»).
Στον υπολογιστή, το ζουμ της σελίδας (Ctrl και + ή −) αλλάζει το DPR: στο 200% το DPR διπλασιάζεται. Ο browser όμως δεν δίνει ξεχωριστά το «επίπεδο ζουμ», εν μέρει για λόγους ιδιωτικότητας (ώστε να μη γίνεται fingerprinting), οπότε βλέπουμε μόνο το συνολικό DPR, που ανακατεύει την πυκνότητα της οθόνης με το ζουμ. Γι' αυτό ακριβώς χρειάζεται η βαθμονόμηση με τον χάρακα: μόνο έτσι ξεχωρίζουμε το πραγματικό DPI από το ζουμ.
Σε tablet και κινητά, το pinch-zoom δεν αλλάζει το DPR (μένει σταθερό, όσο το φυσικό της συσκευής), αλλά το διαβάζουμε από το visualViewport.scale. Το ίδιο ισχύει και για το pinch με trackpad στον υπολογιστή. Έτσι, όποιον τρόπο ζουμ κι αν χρησιμοποιήσεις, ο υπολογισμός μένει σωστός: πολλαπλασιάζουμε το DPR με το visualViewport.scale (όπου υπάρχει) για να βρούμε πόσα device pixel αντιστοιχούν τελικά σε ένα CSS pixel.
Τώρα στη σελίδα: DPR — · visualViewport.scale —