Questa pagina contiene la traduzione dell'articolo "A tale of two viewports" di Peter-Paul Koch. L'articolo originale si trova nel sito www.quirksmode.org, a questo indirizzo.

Racconto di due viewports - parte seconda

In questa miniserie, spiegherò il comportamento dei viewports e delle larghezze di alcuni importanti elementi, come l'elemento <html>, la finestra del browser e lo schermo.

Questa pagina parla di browser per dispositivi mobili. Se sei del tutto nuovo al mondo mobile, ti consiglio di leggere la parte prima riguardante i browser desktop, che ti fornirà le basi per muoverti in un ambiente familiare.

Il problema dei browser mobili

Quando si mettono a confronto i browser mobili con quelli desktop, la differenza più ovvia è nella dimensione dello schermo. I browser mobili possono visualizzare un sito ottimizzato per desktop in maniera molto limitata rispetto ai browser desktop: devono zoomare "all'indietro" finché il testo non diventa così piccolo da risultare illegibile, oppure visualizzano solo la piccola porzione del sito che entra nello schermo.

Lo schermo di un dispositivo mobile è molto più piccolo di uno schermo desktop; si possono considerare circa 400px di larghezza al massimo, a volte anche molto meno. (Alcuni telefoni riportano larghezze maggiori, ma mentono - o almeno forniscono un'informazione inutile.)

Il gap tra desktop e mobile sarà colmato da alcuni tablet di livello intermedio, come l'iPad o l'atteso HP basato su webOS, ma ciò non sposta la questione fondamentale: i siti devono funzionare anche sui dispositivi mobili, quindi dobbiamo riuscire a farli apparire bene su uno schermo piccolo.

I problemi più importanti riguardano i CSS, soprattutto le dimensioni del viewport. Se copiassimo il modello desktop uno-a-uno, il nostro CSS comincerebbe ad incepparsi orribilmente.

Torniamo all'esempio della nostra barra laterale di larghezza width:10%. Se i browser mobili si comportassero esattamente come quelli desktop, assegnerebbero all'elemento una larghezza di 40px al massimo, che però sarebbe decisamente troppo piccola. Il tuo layout liquido risulterebbe orribilmente "strizzato".

Un modo per risolvere il problema è creare per i browser mobili una versione del sito dedicata. Anche senza valutare se la cosa abbia senso, il problema pratico è che solo pochissimi sviluppatori di siti sono esperti a sufficienza da servire adeguatamente i dispositivi mobili.

I produttori di browser vogliono offrire ai propri clienti l'esperienza migliore possibile, che al momento significa "più possibile simile al desktop". Quindi è risultato indispensabile, da parte loro, ricorrere a qualche "gioco di prestigio".

I due viewport

Insomma, il viewport è troppo stretto per essere utilizzato come base per il layout CSS. La soluzione ovvia è renderlo più ampio. Questo, però, richiede che sia suddiviso in due entità differenti: il visual viewport e il layout viewport.

George Cummins spiega il concetto che è alla base di questa suddivisione su Stack Overflow:

Immagina il layout viewport come una grande immagine che non cambia dimensioni né forma. Ora immagina di avere una cornice attraverso cui guardi quell'immagine. La piccola cornice è contornata da un materiale opaco che oscura tutto tranne una porzione dell'immagine grande. La porzione di immagine che riesci a vedere attraverso la cornice è il visual viewport. Puoi allontanarti dall'immagine grande continuando a tenere in mano la cornice (zoom out) per vedere l'immagine completa, oppure puoi avvicinarti (zoom in) per vederne solo una porzione. Puoi anche cambiare l'orientamento della cornice, ma la dimensione e la forma dell'immagine grande (layout viewport) resta inalterata.

Leggi anche questa spiegazione di Chris.

Il visual viewport è la parte della pagina correntemente visualizzata sullo schermo. L'utente può effettuare uno scorrimento per cambiare la parte di pagina visualizzata, oppure zoomare per modificare la dimensione del visual viewport.

In ogni caso, il layout CSS, in particolare le larghezze percentuali, è calcolato relativamente al layout viewport, che è notevolmente più ampio del visual viewport.

Pertanto l'elemento <html> prende inizialmente la larghezza del layout viewport, e il tuo CSS è interpretato come se lo schermo fosse molto più ampio dello schermo del dispositivo. Questo assicura che il layout del tuo sito si comporti proprio come si comporta in un browser desktop.

Quanto è grande il layout viewport? Dipende dal browser. Safari iPhone utilizza 980px, Opera 850px, Android WebKit 800px, e IE 974px.

Alcuni browsers hanno un comportamento peculiare:

Zoomare

Entrambi i viewport sono misurati in pixel CSS, ovviamente. Ma mentre le dimensioni del visual viewport cambiano con lo zoom (se zoomi avanti, un numero minore di pixel CSS entrano nello schermo), quelle del layout viewport restano invariate. (Se così non fosse, la tua pagina subirebbe un continuo reflow poiché verrebbero ricalcolate le larghezze percentuali.)

Capire il layout viewport

Per capire le dimensioni del layout viewport dobbiamo dare uno sguardo a ciò che succede con un livello di zoom che rende visibile tutta la pagina. Molti browser mobili mostrano le pagine inizialmente in questa modalità (che chiamiamo "fully zoomed-out mode").

Il punto è questo: i browser hanno scelto le dimensioni del layout viewport in maniera tale che esso copra completamente lo schermo in "fully zoomed-out mode" (e sia quindi uguale al visual viewport).

Così la larghezza e l'altezza del layout viewport sono uguali a qualunque cosa possa essere visualizzata sullo schermo in "fully zoomed-out mode". Quando l'utente zooma avanti queste dimensioni restano invariate.

La larghezza del layout viewport è sempre la stessa. Se ruoti il telefono, il visual viewport cambia, ma il browser si adatta al nuovo orientamento zoomando in maniera tale che il layout viewport sia di nuovo largo quanto il visual viewport.

Ciò ha delle conseguenze sull'altezza del layout viewport, che ora è inferiore a quella dell'orientamento verticale. Ma gli sviluppatori web non si preoccupano dell'altezza, solo della larghezza.

Misurare il layout viewport

Abbiamo dunque due viewport che vogliamo misurare. È una grande fortuna che la Guerra dei Browser ci abbia dato due coppie di proprietà.

document.documentElement.clientWidth e -Height contengono le dimensioni del layout viewport.

L'orientamento ha importanza per l'altezza, ma non per la larghezza.

Misurare il visual viewport

Per quanto riguarda il visual viewport, esso è misurato da window.innerWidth/Height. Ovviamente le misure cambiano quando l'utente effettua una zoomata, poiché un numero maggiore o minore di pixel CSS entrano nello schermo.

Sfortunatamente questa è un'"area di incompatibilità"; molti browsers devono ancora aggiungere il supporto per la misura del visual viewport. Di più, nessun browser memorizza queste misure in nessun'altra coppia di proprietà, quindi scommetto che window.innerWidth/Height è uno standard, sebbene mal supportato.

Lo schermo

Come in ambiente desktop, screen.width/height forniscono la dimensione dello schermo, in device pixels. Come in ambiente desktop, come sviluppatore non avrai mai bisogno di questa informazione. Non ti interessa la dimensione fisica dello schermo, ma quanti pixel CSS entrano in esso.

Il livello di zoom

Conoscere il livello di zoom direttamente è impossibile, ma puoi ricavarlo dividendo screen.width per window.innerWidth. Naturalmente ciò funziona se entrambe le proprietà sono perfettamente supportate.

Fortunatamente il livello di zoom non è importante. Ciò che ti serve sapere è quanti pixel CSS entrano nello schermo nella situazione corrente. E puoi trovare tale informazione in window.innerWidth — se è supportata correttamente.

Scrolling offset

Un'altra informazione di cui hai bisogno è la posizione attuale del visual viewport relativamente al layout viewport. Si tratta dello scrolling offset e, proprio come per il desktop, è contenuta in window.pageX/YOffset.

L'elemento <html>

Proprio come in ambito desktop, document.documentElement.offsetWidth/Height fornisce la dimensione totale dell'elemento <html> in pixel CSS.

Media queries

Le media queries funzionano esattamente come in ambiente desktop. width/height utilizzano come riferimento il layout viewport e sono misurate in pixel CSS, device-width/height utilizzano lo schermo e sono misurate in device pixels.

In altre parole, width/height rispecchiano i valori di document.documentElement.clientWidth/Height, mentre device-width/height rispecchiano i valori di screen.width/height. (Questo avviene realmente in tutti i browser, anche se i valori non sono corretti.)

Ora, qual è la misura più utile per noi sviluppatori? Il punto è questo: non lo so.

Inizialmente ho ritenuto che device-width fosse la più importante, dal momento che fornisce informazioni sul dispositivo che vorremmo utilizzare. Ad esempio, potresti modificare la larghezza del tuo layout per adattarti alla larghezza del dispositivo. Ad ogni modo, potresti farlo anche utilizzando <meta viewport>; non è affatto necessario usare la media query device-width.

Insomma, alla fine è forse width la media query più importante? Forse; fornisce degli indizi su quale sia la larghezza di pagina che il produttore del browser ritiene sia più adatta per questo dispositivo. Ma questa cosa è un po' vaga, e la media query sulla larghezza width non fornisce in realtà altre informazioni.

In definitiva, sono indeciso. Al momento credo che le media queries siano importanti per capire se si è su un desktop, un tablet o un dispositivo mobile, ma non così utili per distinguere tra i vari tablet e smartphone.

O qualcosa del genere.

Coordinate degli eventi

Le coordinate degli eventi funzionano più o meno come in ambiente desktop. Purtroppo, dei dodici browser testati, solo due, Symbian WebKit e Iris, acquisiscono le tre coppie di coordinate in maniera esatta. Tutti gli altri browser manifestano problemi più o meno seri.

pageX/Y sono ancora relative alla pagina in pixel CSS, e questa è di gran lunga la più utile delle tre coppie di proprietà, proprio come in ambiente desktop.

clientX/Y sono relative al visual viewport ed espresse in pixel CSS. Ciò ha un senso, anche se non sono del tutto certo della sua utilità.

screenX/Y sono relative allo schermo in device pixels. Naturalmente, rappresentano lo stesso riferimento usato da clientX/Y, e i device pixels sono inutili. Perciò non abbiamo bisogno di preoccuparci troppo di screenX/Y; è inutile esattamente come lo era per il desktop.

Meta viewport

Discutiamo infine il <meta name="viewport" content="width=320">; originariamente un'estensione Apple ma nel frattempo copiato da molti più browser. È pensato per ridimensionare il layout viewport. Per capire perché ciò sia necessario, facciamo un passo indietro.

Supponi di creare una pagina senza assegnare alcuna larghezza agli elementi in essa contenuti. In tale situazione, essi si estendono a coprire il 100% della larghezza del layout viewport. La maggior parte dei browser effettuano uno zoom allo scopo di mostrare sullo schermo l'intero layout viewport, ottenendo questo effetto:

Tutti gli utenti effettuerebbero immediatamente un ingrandimento; il che funziona, ma molti browser mantengono intatta la larghezza degli elementi, rendendo difficile leggere il testo.

(Un'eccezione significativa a questo comportamento è rappresentata da Android WebKit, che riduce la dimensione degli elementi contenenti testo in maniera tale da farli entrare interamente nello schermo. Questo è assolutamente straordinario, e credo che tutti gli altri browser dovrebbero copiare questo comportamento. Lo documenterò con completezza in seguito.)

Si può tentare di impostare html {width: 320px}. In questo modo l'elemento <html> si restringe, e con lui tutti gli altri elementi, che ora prendono il 100% di 320px. Ciò funziona quando l'utente effettua l'ingrandimento, ma non all'inizio, quando viene mostrata una pagina in "fully zoomed-out mode" che per la gran parte non contiene nulla.

Proprio per aggirare questo problema, Apple ha inventato il tag meta viewport. Quando imposti <meta name="viewport" content="width=320">, ciò che stai impostando a 320px è la larghezza del layout viewport. Ora anche lo stato iniziale della pagina risulta corretto.

Puoi impostare la larghezza del layout viewport al valore che vuoi, incluso device-width. Quest'ultimo prende come riferimento screen.width (in device pixels) e ridimensiona il layout viewport di conseguenza.

C'è però un inganno. A volte il valore dichiarato di screen.width non ha molto senso perché il conteggio dei pixel è troppo alto. Ad esempio, il Nexus One ha formalmente una larghezza di 480px, ma gli ingegneri di Google hanno deciso che fornire una larghezza di 480px al layout viewport quando si usa device-width è un po' troppo. L'hanno così ridotta a 2/3, cosicché device-width dà una larghezza di 320px, proprio come sull'iPhone.

Se, come si sente dire, il nuovo iPhone potrà vantare un numero di pixel maggiore (che non vorrà dire necessariamente uno schermo più grande!), non sarei sorpreso se la Apple dovesse copiare questo comportamento. device-width potrebbe finire per significare semplicemente 320px.

Approfondimenti

Diversi argomenti correlati a quello trattato richiedono di essere ulteriormente approfonditi: