Pubblicato: 22 agosto 2012, ultimo aggiornamento: 14 aprile 2025
Con così tanti dispositivi sul mercato, è disponibile una gamma molto ampia di densità di pixel dello schermo. Gli sviluppatori di applicazioni devono supportare una serie di densità di pixel, il che può essere piuttosto impegnativo. Sul web mobile, le difficoltà sono aggravate da diversi fattori:
- Ampia gamma di dispositivi con diversi fattori di forma.
- Larghezza di banda della rete e durata della batteria limitate.
In termini di immagini, l'obiettivo degli sviluppatori web è pubblicare le immagini di migliore qualità nel modo più efficiente possibile. Di seguito sono riportate alcune tecniche utili per farlo ora e in futuro.
Evita le immagini, se possibile
Prima di dare per scontato che devi includere un'immagine, ricorda che il web offre numerose tecnologie efficaci che sono in gran parte indipendenti da risoluzione e DPI.
Nello specifico, testo, SVG e gran parte del CSS "funzionano e basta" grazie alla funzionalità di ridimensionamento automatico dei pixel del web con devicePixelRatio
.
Detto questo, non è sempre possibile evitare le immagini raster. Ad esempio, potresti ricevere risorse che sarebbero piuttosto difficili da replicare in SVG o CSS puri. Potresti avere a che fare con una fotografia. Sebbene sia possibile convertire automaticamente un'immagine in un file SVG, la vettorizzazione delle fotografie ha poco senso perché le versioni ingrandite di solito non hanno un bell'aspetto.
Cronologia della densità di pixel
All'inizio, i display dei computer avevano una densità di pixel di 72 o 96 dpi (punti per pollice).
La densità di pixel dei display è migliorata gradualmente, in gran parte grazie all'evoluzione dei dispositivi mobili, poiché in genere gli utenti tengono gli smartphone più vicini al viso, rendendo i pixel più visibili. Entro il 2008, gli smartphone da 150 dpi erano la nuova norma. La densità del display è aumentata ulteriormente e oggi gli smartphone hanno display con una risoluzione di 300 dpi.
In pratica, le immagini a bassa densità dovrebbero avere lo stesso aspetto sulle nuove schermate come su quelle vecchie, ma rispetto alle immagini nitide ad alta densità che gli utenti sono abituati a vedere, le immagini a bassa densità sembrano sgradevoli e pixelated. Di seguito è riportata una simulazione approssimativa dell'aspetto di un'immagine 1x su un display 2x. Al contrario, l'immagine 2x è di buona qualità.
Pixel 1x | Pixel 2x |
![]() |
![]() |
Pixel sul web
Quando è stato progettato il web, il 99% dei display aveva una risoluzione di 96 dpi e sono state prese poche disposizioni per le varianti. Ora che abbiamo una grande variabilità di dimensioni e densità dello schermo, abbiamo bisogno di un modo standard per ottimizzare le immagini su tutti gli schermi.
La specifica HTML ha risolto questo problema definendo un pixel di riferimento utilizzato dai produttori per determinare le dimensioni di un pixel CSS.
Utilizzando il pixel di riferimento, un produttore può determinare le dimensioni del pixel fisico del dispositivo rispetto al pixel standard o ideale. Questo rapporto è chiamato proporzioni pixel del dispositivo.
Calcolare il rapporto pixel del dispositivo
Supponiamo che uno smartphone abbia uno schermo con una dimensione fisica dei pixel di 180 pixel per pollice (ppi). Il calcolo del rapporto pixel del dispositivo richiede tre passaggi:
Confronta la distanza effettiva a cui è tenuto il dispositivo con la distanza per il pixel di riferimento.
In base alle specifiche, sappiamo che a 71 cm l'ideale è 96 pixel per pollice. Con un cellulare, sappiamo che i volti delle persone sono più vicini ai loro dispositivi rispetto a laptop e computer. Per le seguenti equazioni, stimiamo che la distanza sia di 45 cm.
Moltiplica il rapporto di distanza per la densità standard (96 ppi) per ottenere la densità di pixel ideale per la distanza indicata.
idealPixelDensity = (28/18) * 96 = 150 pixel per pollice (circa)
Prendi il rapporto tra la densità dei pixel fisica e la densità dei pixel ideale per ottenere il rapporto pixel del dispositivo.
devicePixelRatio = 180/150 = 1,2

Ora, quando un browser deve sapere come ridimensionare un'immagine in base alle dimensioni dello schermo, in base alla risoluzione ideale o standard, fa riferimento alle proporzioni pixel del dispositivo di 1,2. Ciò significa che per ogni pixel ideale, questo dispositivo ha 1,2 pixel fisici. La formula per passare dai pixel ideali (come definiti dalle specifiche web) a quelli fisici (punti sullo schermo del dispositivo) è la seguente:
physicalPixels = window.devicePixelRatio * idealPixels
In passato, i fornitori di dispositivi tendevano ad arrotondare i devicePixelRatios
(DPR). Gli iPhone e gli iPad di Apple riportano un DPR pari a 1, mentre i loro equivalenti Retina riportano 2. La specifica CSS consiglia di
l'unità di misura dei pixel si riferisce al numero intero di pixel del dispositivo che approssima al meglio il pixel di riferimento.
Uno dei motivi per cui i rapporti arrotondati possono essere migliori è che possono portare a meno artefatti subpixel.
Tuttavia, la realtà del panorama dei dispositivi è molto più varia e spesso gli smartphone Android hanno un DPR di 1, 5. Il tablet Nexus 7 ha un DPR di circa 1,33, ottenuto con un calcolo simile a quello dell'esempio precedente. In futuro, prevediamo di aggiungere altri dispositivi con DPR variabili. Per questo motivo, non dovresti mai presumere che i tuoi clienti abbiano DPR interi.
Tecniche di immagine HiDPI
Esistono molte tecniche per risolvere il problema di mostrare le immagini di miglior qualità il più rapidamente possibile, che rientrano in due categorie generali:
- Ottimizzazione di singole immagini.
- Ottimizzazione della selezione tra più immagini.
Approcci con una singola immagine: utilizza un'immagine, ma fai qualcosa di intelligente. Questi approcci hanno lo svantaggio che devi inevitabilmente sacrificare le prestazioni, poiché devi scaricare immagini HiDPI, anche su dispositivi meno recenti con DPI inferiori. Ecco alcuni approcci per il caso singolo dell'immagine:
- Immagine HiDPI molto compressa
- Formato dell'immagine assolutamente fantastico
- Formato di immagine progressivo
Approcci con più immagini: utilizza più immagini, ma fai qualcosa di intelligente per scegliere quali caricare. Questi approcci hanno un overhead intrinseco per lo sviluppatore, che deve creare più versioni dello stesso asset e poi elaborare una strategia decisionale. Le opzioni sono:
- JavaScript
- Pubblicazione lato server
- Query sui media CSS
- Funzionalità del browser integrate (
image-set()
,<img srcset>
)
Immagine HiDPI molto compressa
Le immagini rappresentano già il 60% della larghezza di banda utilizzata per scaricare un sito web medio. Se pubblichi immagini HiDPI per tutti i clienti, questo numero aumenta. Quanto può crescere?
Ho eseguito alcuni test che hanno generato frammenti di immagini 1x e 2x con qualità JPEG a 90, 50 e 20.
Da questo piccolo e non scientifico campionamento, sembra che la compressione delle immagini di grandi dimensioni offra un buon compromesso tra qualità e dimensioni. A mio avviso, le immagini con una compressione elevata sono addirittura migliori di quelle non compresse.
Detto questo, pubblicare immagini 2x di bassa qualità e altamente compresse su dispositivi 2x è peggio che pubblicarne di qualità superiore e questo approccio comporterebbe penalizzazioni della qualità delle immagini. Se confronti le immagini quality: 90
con quelle quality: 20
, noterai una diminuzione della nitidezza e un aumento della granulosità. Gli artefatti con quality:20
potrebbero non essere accettabili
se sono importanti immagini di alta qualità (ad esempio, un'applicazione di visualizzatore di foto) o per gli sviluppatori di app che non vogliono scendere a compromessi.
Questo confronto è stato effettuato interamente con file JPEG compressi. Vale la pena ricordare che esistono molti compromessi tra i formati delle immagini ampiamente implementati (JPEG, PNG, GIF), il che ci porta a…
WebP: formato di immagine assolutamente fantastico
WebP è un formato di immagine molto accattivante che comprime molto bene le immagini mantenendone un'elevata fedeltà.
Un modo per verificare il supporto di WebP è utilizzare JavaScript. Carica un'immagine di 1 px con data-uri
, attendi l'attivazione di eventi di caricamento o di errore e poi verifica che le dimensioni siano corrette. Modernizr è fornito con un script di rilevamento delle funzionalità, disponibile con Modernizr.webp
.
Tuttavia, un modo migliore per farlo è direttamente nel CSS utilizzando la funzione image(). Pertanto, se hai un'immagine WebP e un'immagine JPEG di riserva, puoi scrivere quanto segue:
#pic {
background: image("foo.webp", "foo.jpg");
}
Questo approccio presenta alcuni problemi. Innanzitutto, image()
non è affatto implementato su larga scala. In secondo luogo, anche se la compressione WebP supera di gran lunga quella JPEG, si tratta comunque di un miglioramento relativamente incrementale: le dimensioni sono ridotte di circa il 30% in base a questa galleria WebP. Pertanto, WebP
da solo non è sufficiente per risolvere il problema dell'elevato DPI.
Formati di immagini progressive
I formati delle immagini progressive come JPEG 2000, JPEG progressivo, PNG progressivo e GIF hanno il vantaggio (alquanto dibattuto) di mostrare l'immagine prima che venga caricata completamente. Potrebbero comportare un sovraccarico delle dimensioni, anche se esistono prove contrastanti in merito. Jeff Atwood ha affermato che la modalità progressiva "aumenta di circa il 20% le dimensioni delle immagini PNG e di circa il 10% le dimensioni delle immagini JPEG e GIF". Tuttavia, Stoyan Stefanov ha affermato che per i file di grandi dimensioni, la modalità progressiva è più efficiente (nella maggioranza dei casi).
A prima vista, le immagini progressive sembrano molto promettenti nel contesto della pubblicazione di immagini della migliore qualità il più rapidamente possibile. L'idea è che il browser possa interrompere il download e la decodifica di un'immagine quando sa che i dati aggiuntivi non miglioreranno la qualità dell'immagine (ovvero tutti i miglioramenti della fedeltà sono a livello di subpixel).
Sebbene le connessioni siano rapide da terminare, spesso è costoso riavviarle. Per un sito con molte immagini, l'approccio più efficiente è mantenere attiva una singola connessione HTTP, riutilizzandola il più a lungo possibile. Se la connessione viene interrotta prematuramente perché un'immagine è stata scaricata in misura sufficiente, il browser deve creare una nuova connessione, che può essere molto lenta in ambienti a bassa latenza.
Una soluzione alternativa è utilizzare la richiesta Intervallo HTTP, che consente ai browser di specificare un intervallo di byte da recuperare. Un browser intelligente potrebbe effettuare una richiesta HEAD per recuperare l'intestazione, elaborarla, decidere quanta parte dell'immagine è effettivamente necessaria ed eseguire il recupero. Purtroppo, l'intervallo HTTP è supportato male nei server web, il che rende poco pratico questo approccio.
Infine, un'ovvia limitazione di questo approccio è che non puoi scegliere quale immagine caricare, ma solo variare la fedeltà della stessa immagine. Di conseguenza, non viene affrontato il caso d'uso "Art direction".
Utilizzare JavaScript per decidere quale immagine caricare
L'approccio più immediato per decidere quale immagine caricare è utilizzare JavaScript nel client. Questo approccio ti consente di scoprire tutto sul tuo user agent e di adottare il comportamento corretto. Puoi determinare il rapporto pixel del dispositivo con window.devicePixelRatio
, ottenere la larghezza e l'altezza dello schermo e persino eseguire alcuni controlli sulla connessione di rete con navigator.connection o inviare una richiesta falsa, come fa la libreria foresight.js. Dopo aver raccolto tutte queste informazioni, puoi decidere quale immagine caricare.
Esistono circa un milione di librerie JavaScript che impiegano questa tecnica. Purtroppo, nessuno di questi è particolarmente eccezionale.
Un grande svantaggio è che il caricamento delle immagini viene ritardato fino al termine del parser di look-ahead. Ciò significa essenzialmente che il download delle immagini non inizierà nemmeno dopo l'attivazione dell'evento pageload
. Scopri di più in questo
articolo di Jason Grigsby.
Decidere quale immagine caricare sul server
Puoi rimandare la decisione al lato server scrivendo gestori delle richieste personalizzati per ogni immagine pubblicata. Un gestore di questo tipo controllerebbe il supporto di Retina in base allo User-Agent (l'unica informazione condivisa con il server). Poi, a seconda che la logica lato server voglia pubblicare asset HiDPI, carica l'asset appropriato (nominato in base a una convenzione nota).
Purtroppo, l'User-Agent non fornisce necessariamente informazioni sufficienti per decidere se un dispositivo deve ricevere immagini di alta o bassa qualità. Inoltre, è necessario evitare qualsiasi soluzione che utilizzi User-Agent
per prendere decisioni di stile.
Utilizzare le query sui media CSS
Poiché sono dichiarative, le query sui media CSS ti consentono di dichiarare la tua intenzione e lasciare che il browser agisca per tuo conto. Oltre all'uso più comune delle query supporti, ovvero la corrispondenza alle dimensioni del dispositivo, puoi anche eseguire la corrispondenza a devicePixelRatio
. La query sui media associata è
device-pixel-ratio e ha varianti minime e massime associate, come
potrebbe essere previsto.
Se vuoi caricare immagini ad alto DPI e il rapporto tra pixel del dispositivo supera una soglia, ecco cosa puoi fare:
#my-image { background: (low.png); }
@media only screen and (min-device-pixel-ratio: 1.5) {
#my-image { background: (high.png); }
}
La situazione si complica un po' con tutti i prefissi dei fornitori, soprattutto a causa delle ampie differenze di posizionamento dei prefissi "min" e "max":
@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);
}
}
Con questo approccio, puoi recuperare i vantaggi dell'analisi anticipata, che è andata persa con la soluzione JavaScript. Inoltre, hai la flessibilità di scegliere i punti di interruzione adattabili (ad esempio, puoi avere immagini con DPI bassi, medi e alti), che non era possibile con l'approccio lato server.
Purtroppo è ancora un po' complicato e genera CSS dall'aspetto strano o richiede l'elaborazione preliminare. Inoltre, questo approccio è limitato alle proprietà CSS, quindi non è possibile impostare un <img src>
e le immagini devono essere tutte elementi con uno sfondo. Infine, se ti basi esclusivamente sul rapporto pixel del dispositivo, potresti trovarti in situazioni in cui il tuo smartphone ad alta risoluzione scarica una risorsa immagine di grandi dimensioni con il doppio della risoluzione su una connessione EDGE. Non si tratta della migliore esperienza utente.
Poiché image-set()
è una funzione CSS, non risolve il problema per i tag <img>
. Inserisci @srcset, che risolve il problema.
La sezione successiva approfondisce image-set
e srcset
.
Funzionalità del browser per il supporto di DPI elevati
In definitiva, l'approccio al supporto di DPI elevati dipende dai tuoi requisiti specifici. Tutti gli approcci sopra menzionati presentano degli svantaggi.
Ora che image-set
e srcset
sono ampiamente supportati, sono le migliori soluzioni. Esistono altre best practice che possono aiutarci a migliorare la situazione per i browser meno recenti.
Quali sono le differenze tra i due? image-set()
è una funzione CSS, appropriata per l'utilizzo come valore della proprietà CSS background.
srcset
è un attributo specifico per gli elementi <img>
, con sintassi simile.
Entrambi i tag consentono di specificare dichiarazioni di immagini, ma l'attributo srcset
consente anche di configurare l'immagine da caricare in base alle dimensioni del viewport.
Best practice per gli annunci insiemi di immagini
La sintassi image-set()
accetta una o più dichiarazioni di immagini separate da virgola,
che consistono in una stringa URL o nella funzione url()
seguita dalla risoluzione appropriata. Ad esempio:
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
);
Questo indica al browser che ci sono due immagini tra cui scegliere. Un'immagine è ottimizzata per i display 1x e l'altra per i display 2x. Il browser sceglie quale caricare in base a una serie di fattori, che possono includere anche la velocità della rete, se è abbastanza intelligente.
Oltre a caricare l'immagine corretta, il browser la ridimensiona di conseguenza. In altre parole, il browser presume che le immagini 2x siano il doppio delle immagini 1x e riduce l'immagine 2x di un fattore 2, in modo che l'immagine abbia le stesse dimensioni sulla pagina.
Anziché specificare 1x, 1,5x o Nx, puoi anche specificare una determinata densità di pixel del dispositivo in DPI.
Se temi che i browser meno recenti non supportino la proprietà image-set
, puoi aggiungere un'opzione di riserva per assicurarti che venga visualizzata un'immagine. Ad esempio:
/* 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
);
Questo codice di esempio carica l'asset appropriato nei browser che supportano gli image-set e, in caso contrario, passa all'asset 1x.
A questo punto, potresti chiederti perché non utilizzare semplicemente il polyfill (ovvero creare uno shim JavaScript per) image-set()
e chiudere la questione. A quanto pare, è abbastanza difficile implementare polyfill efficienti per le funzioni CSS. Per una spiegazione dettagliata del motivo, consulta questa discussione su www-style.
Srcset immagine
Oltre alle dichiarazioni fornite da image-set
,
l'elemento srcset
accetta anche i valori di larghezza e altezza che corrispondono alle
dimensioni della visualizzazione, tentando di pubblicare la versione più pertinente.
<img alt="my awesome image"
src="banner.jpeg"
srcset="banner-HD.jpeg 2x, banner-phone.jpeg 640w, banner-phone-HD.jpeg 640w 2x">
Questo esempio pubblica banner-phone.jpeg
per i dispositivi con larghezza dell'area visibile inferiore a 640 px, banner-phone-HD.jpeg
per i dispositivi con schermo piccolo e DPI elevato,banner-HD.jpeg
per i dispositivi con DPI elevato e schermo superiore a 640 px ebanner.jpeg
per tutti gli altri.
Utilizzare image-set per gli elementi immagine
Potrebbe essere allettante sostituire gli elementi img con <div>
s
con sfondi e utilizzare l'approccio di immagine insiemi. Questa operazione funziona, ma con alcune limitazioni. Lo svantaggio è che il tag <img>
ha un valore semantico di lunga durata. In pratica, questo è importante per l'accessibilità e per i crawler web.
Puoi utilizzare la proprietà CSS content, che ridimensiona automaticamente l'immagine in base a devicePixelRation
. Ad esempio:
<div id="my-content-image"
style="content: -webkit-image-set(
url(icon1x.jpg) 1x,
url(icon2x.jpg) 2x);">
</div>
Polyfill srcset
Una funzionalità utile di srcset
è che è dotato di un valore predefinito.
Se l'attributo srcset non è implementato, tutti i browser devono elaborare l'attributo src. Inoltre, poiché si tratta solo di un attributo HTML, è possibile creare polyfill con JavaScript.
Questo polyfill è dotato di test di unità per garantire che sia il più vicino possibile alla specifica. Inoltre, sono stati implementati controlli che impediscono al polyfill di eseguire codice se la proprietà srcset è implementata in modo nativo.
Conclusione
La soluzione migliore per le immagini ad alta DPI è optare per SVG e CSS. Tuttavia, non è sempre una soluzione realistica, soprattutto per i siti web con molte immagini.
Gli approcci in JavaScript, CSS e le soluzioni lato server hanno i loro punti di forza
e di debolezza. L'approccio più promettente è utilizzare image-set
e srcset
.
Per riepilogare, i miei consigli sono i seguenti:
- Per le immagini di sfondo, utilizza image-set con le alternative appropriate per i browser che non lo supportano.
- Per le immagini dei contenuti, utilizza un polyfill srcset o ricorre all'utilizzo di image-set (vedi sopra).
- Per le situazioni in cui sei disposto a sacrificare la qualità delle immagini, valuta la possibilità di utilizzare immagini 2x molto compresse.