Le query supporti sono ottime, ma…
Le media query sono fantastiche, una manna dal cielo per gli sviluppatori di siti web che vogliono apportare piccole modifiche ai loro fogli di stile per offrire un'esperienza migliore agli utenti su dispositivi di varie dimensioni. Le query supporti ti consentono essenzialmente di personalizzare il CSS del tuo sito in base alle dimensioni dello schermo. Prima di leggere questo articolo, scopri di più sul design responsivo e consulta alcuni ottimi esempi di utilizzo delle query supporti qui: mediaqueri.es.
Come sottolinea Brad Frost in un articolo precedente, la modifica dell'aspetto è solo uno dei tanti aspetti da considerare quando si sviluppa per il web mobile. Se l'unica cosa che fai quando crei il tuo sito web mobile è personalizzare il layout con le media query, allora si verifica la seguente situazione:
- Tutti i dispositivi ricevono gli stessi contenuti JavaScript, CSS e asset (immagini, video), con conseguenti tempi di caricamento più lunghi del necessario.
- Tutti i dispositivi ricevono lo stesso DOM iniziale, il che potrebbe costringere gli sviluppatori a scrivere CSS eccessivamente complessi.
- Poca flessibilità per specificare interazioni personalizzate in base a ogni dispositivo.
Le web app hanno bisogno di più delle media query
Non fraintendermi. Non odio il design reattivo tramite le media query e penso che abbia un ruolo importante. Inoltre, alcuni dei problemi sopra menzionati possono essere risolti con approcci come immagini adattabili, caricamento dinamico degli script e così via. Tuttavia, a un certo punto, potresti ritrovarti a fare troppe modifiche incrementali e potrebbe essere meglio pubblicare versioni diverse.
Man mano che le UI che crei diventano più complesse e ti avvicini alle web app a una sola pagina, vorrai fare di più per personalizzare le UI per ogni tipo di dispositivo. Questo articolo ti insegnerà a eseguire queste personalizzazioni con il minimo sforzo. L'approccio generale consiste nel classificare il dispositivo del visitatore nella classe di dispositivi corretta e pubblicare la versione appropriata per quel dispositivo, massimizzando il riutilizzo del codice tra le versioni.
Quali classi di dispositivi stai prendendo di mira?
Esistono tantissimi dispositivi connessi a internet e quasi tutti hanno browser. La difficoltà sta nella loro diversità: laptop Mac, workstation Windows, iPhone, iPad, smartphone Android con input tattile, rotelle di scorrimento, tastiere, input vocale, dispositivi con sensibilità alla pressione, smartwatch, tostapane, frigoriferi e molti altri. Alcuni di questi dispositivi sono onnipresenti, mentre altri sono molto rari.
Per creare una buona esperienza utente, devi sapere chi sono i tuoi utenti e quali dispositivi utilizzano. Se crei un'interfaccia utente per un utente desktop con mouse e tastiera e la dai a un utente di smartphone, la tua interfaccia sarà frustrante perché è progettata per un'altra dimensione dello schermo e un'altra modalità di input.
Esistono due approcci estremi:
Crea una versione che funzioni su tutti i dispositivi. Di conseguenza, l'esperienza utente ne risentirà, poiché i diversi dispositivi hanno considerazioni di progettazione diverse.
Crea una versione per ogni dispositivo che vuoi supportare. Ci vorrà un'eternità, perché creerai troppe versioni della tua applicazione. Inoltre, quando arriverà il prossimo nuovo smartphone (cosa che accade circa ogni settimana), sarai costretto a creare un'altra versione.
Esiste un compromesso fondamentale: più categorie di dispositivi hai, migliore sarà l'esperienza utente che puoi offrire, ma maggiore sarà il lavoro necessario per progettare, implementare e mantenere.
Creare una versione separata per ogni classe di dispositivi che scegli potrebbe essere una buona idea per motivi di rendimento o se le versioni che vuoi pubblicare per le diverse classi di dispositivi variano notevolmente. In caso contrario, il responsive web design è un approccio perfettamente ragionevole.
Una potenziale soluzione
Ecco una soluzione di compromesso: classifica i dispositivi in categorie e progetta la migliore esperienza possibile per ogni categoria. Le categorie che scegli dipendono dal tuo prodotto e dall'utente target. Ecco una classificazione di esempio che copre bene i dispositivi web più diffusi oggi.
- schermi piccoli + tocco (principalmente smartphone)
- schermi grandi + tocco (principalmente tablet)
- schermi grandi + tastiera/mouse (principalmente desktop/laptop)
Questa è solo una delle tante suddivisioni possibili, ma è una di quelle che ha più senso al momento della stesura. Nell'elenco precedente mancano i dispositivi mobili senza touch screen (ad es. feature phone, alcuni e-reader dedicati). Tuttavia, la maggior parte di questi ha installato un software di navigazione da tastiera o di lettura dello schermo, che funzionerà correttamente se crei il tuo sito tenendo presente l'accessibilità.
Esempi di web app specifiche per il fattore di forma
Esistono molti esempi di proprietà web che pubblicano versioni completamente diverse per fattori di forma diversi. La Ricerca Google lo fa, così come Facebook. Le considerazioni a riguardo includono sia il rendimento (recupero asset, rendering delle pagine) sia l'esperienza utente più generale.
Nel mondo delle app native, molti sviluppatori scelgono di personalizzare la propria esperienza in base a una classe di dispositivi. Ad esempio, Flipboard per iPad ha un'interfaccia utente molto diversa rispetto a Flipboard su iPhone. La versione per tablet è ottimizzata per l'utilizzo a due mani e per la rotazione orizzontale, mentre la versione per smartphone è pensata per l'interazione con una sola mano e per la rotazione verticale. Anche molte altre applicazioni per iOS forniscono versioni per smartphone e tablet significativamente diverse, come Things (lista di cose da fare) e Showyou (video social), mostrate di seguito:
Approccio 1: rilevamento lato server
Sul server, abbiamo una comprensione molto più limitata del dispositivo con cui abbiamo a che fare. Probabilmente l'indizio più utile disponibile è la stringa dello user agent, fornita tramite l'intestazione User-Agent in ogni richiesta. Per questo motivo, qui funzionerà lo stesso approccio di sniffing UA. Infatti, i progetti DeviceAtlas e WURFL lo fanno già (e forniscono molte informazioni aggiuntive sul dispositivo).
Purtroppo, ognuno di questi presenta le proprie sfide. WURFL è molto grande, contiene 20 MB di XML e potrebbe comportare un sovraccarico significativo lato server per ogni richiesta. Esistono progetti che dividono l'XML per motivi di rendimento. DeviceAtlas non è open source e richiede una licenza a pagamento per essere utilizzato.
Esistono anche alternative più semplici e senza costi, come il progetto Detect Mobile Browsers. Lo svantaggio, ovviamente, è che il rilevamento dei dispositivi sarà inevitabilmente meno completo. Inoltre, distingue solo tra dispositivi mobili e non mobili, fornendo un supporto limitato per i tablet solo tramite un insieme di modifiche ad hoc.
Approccio n. 2: rilevamento lato client
Possiamo scoprire molte informazioni sul browser e sul dispositivo dell'utente utilizzando il rilevamento delle funzionalità. Gli elementi principali da determinare sono se il dispositivo ha funzionalità touch e se lo schermo è grande o piccolo.
Dobbiamo tracciare una linea di demarcazione per distinguere i dispositivi touch di piccole e grandi dimensioni. E per quanto riguarda i casi limite come il Galaxy Note da 5 pollici? La seguente immagine mostra una serie di dispositivi Android e iOS popolari sovrapposti (con le risoluzioni dello schermo corrispondenti). L'asterisco indica che il dispositivo è o può essere a doppia densità. Anche se la densità di pixel potrebbe essere raddoppiata, CSS continua a segnalare le stesse dimensioni.
Una breve digressione sui pixel in CSS: i pixel CSS sul web mobile non sono gli stessi dei pixel dello schermo. I dispositivi retina iOS hanno introdotto la pratica di raddoppiare la densità di pixel (ad es. iPhone 3GS vs 4, iPad 2 vs 3). Le stringhe UA di Mobile Safari retina continuano a segnalare la stessa larghezza del dispositivo per evitare di interrompere il funzionamento del web. Come altri dispositivi (ad es. Android) ottengono display a risoluzione più elevata, utilizzano lo stesso trucco della larghezza del dispositivo.
A complicare questa decisione, tuttavia, c'è l'importanza di considerare sia la modalità verticale che quella orizzontale. Non vogliamo ricaricare la pagina o caricare script aggiuntivi ogni volta che riorientiamo il dispositivo, anche se potremmo voler eseguire il rendering della pagina in modo diverso.
Nel seguente diagramma, i quadrati rappresentano le dimensioni massime di ciascun dispositivo, risultanti dalla sovrapposizione dei contorni verticale e orizzontale (e dal completamento del quadrato):
Se impostiamo la soglia su 650px, classifichiamo iPhone e Galaxy Nexus come
smalltouch e iPad e Galaxy Tab come "tablet". Il Galaxy
Note androgino in questo caso è classificato come "smartphone" e avrà il layout
dello smartphone.
Pertanto, una strategia ragionevole potrebbe essere la seguente:
if (hasTouch) {
if (isSmall) {
device = PHONE;
} else {
device = TABLET;
}
} else {
device = DESKTOP;
}
Guarda un esempio minimo dell'approccio di rilevamento delle funzionalità in azione.
L'approccio alternativo consiste nell'utilizzare lo sniffing dello user agent per rilevare il tipo di dispositivo. In pratica, crei un insieme di euristiche e le confronti con
il navigator.userAgent dell'utente. Lo pseudocodice ha un aspetto simile
al seguente:
var ua = navigator.userAgent;
for (var re in RULES) {
if (ua.match(re)) {
device = RULES[re];
return;
}
}
Guarda un esempio dell'approccio di rilevamento UA in azione.
Una nota sul caricamento lato client
Se esegui il rilevamento UA sul tuo server, puoi decidere quali CSS, JavaScript e DOM pubblicare quando ricevi una nuova richiesta. Tuttavia, se esegui il rilevamento lato client, la situazione è più complessa. Hai diverse opzioni:
- Reindirizza a un URL specifico per il tipo di dispositivo che contiene la versione per questo tipo di dispositivo.
- Carica dinamicamente gli asset specifici del tipo di dispositivo.
Il primo approccio è semplice e richiede un reindirizzamento come
window.location.href = '/tablet'. Tuttavia, ora alla posizione verranno aggiunte
le informazioni sul tipo di dispositivo, quindi ti consigliamo di utilizzare l'API History per ripulire l'URL. Purtroppo questo
approccio prevede un reindirizzamento, che può essere lento, soprattutto sui dispositivi
mobili.
Il secondo approccio è molto più complesso da implementare. Hai bisogno di un
meccanismo per caricare dinamicamente CSS e JS e (a seconda del browser), potresti
non essere in grado di personalizzare <meta viewport>. Inoltre,
poiché non è presente alcun reindirizzamento, devi utilizzare l'HTML originale
visualizzato. Naturalmente, puoi manipolarlo con JavaScript, ma questa operazione potrebbe
essere lenta e/o poco elegante, a seconda dell'applicazione.
Scegliere il client o il server
Ecco i compromessi tra gli approcci:
Pro client:
- Più a prova di futuro perché basato sulle dimensioni/funzionalità dello schermo anziché su UA.
- Non è necessario aggiornare costantemente l'elenco degli user agent.
Server Pro:
- Controllo completo della versione da pubblicare sui dispositivi.
- Prestazioni migliori: non sono necessari reindirizzamenti dei client o caricamenti dinamici.
La mia preferenza personale è iniziare con device.js e il rilevamento lato client. Man mano che l'applicazione si evolve, se il reindirizzamento lato client si rivela un inconveniente significativo per le prestazioni, puoi rimuovere facilmente lo script device.js e implementare il rilevamento UA sul server.
Introduzione di device.js
Device.js è un punto di partenza per il rilevamento semantico dei dispositivi basato su media query senza richiedere una configurazione speciale lato server, risparmiando tempo e fatica necessari per l'analisi della stringa user agent.
L'idea è di fornire un markup ottimizzato per i motori di ricerca (link
rel=alternate) nella parte superiore di <head> che indichi le versioni del tuo sito che vuoi fornire.
<link rel="alternate" href="http://foo.com" id="desktop"
media="only screen and (touch-enabled: 0)">
Successivamente, puoi eseguire il rilevamento dello user agent lato server e gestire il reindirizzamento della versione in autonomia oppure utilizzare lo script device.js per eseguire il reindirizzamento lato client basato sulle funzionalità.
Per maggiori informazioni, consulta la pagina del progetto device.js e anche un'applicazione fittizia che utilizza device.js per il reindirizzamento lato client.
Suggerimento: MVC con visualizzazioni specifiche per il fattore di forma
A questo punto probabilmente starai pensando che ti sto dicendo di creare tre app completamente separate, una per ogni tipo di dispositivo. No! La condivisione del codice è la chiave.
Speriamo che tu abbia utilizzato un framework simile a MVC, come Backbone, Ember e così via. In questo caso, avrai familiarità con il principio di separazione delle competenze, in particolare con il fatto che la tua UI (livello di visualizzazione) deve essere disaccoppiata dalla tua logica (livello del modello). Se non hai familiarità con questo argomento, inizia con alcune di queste risorse su MVC e su MVC in JavaScript.
La storia cross-device si inserisce perfettamente nel framework MVC esistente. Puoi spostare facilmente le visualizzazioni in file separati, creando una visualizzazione personalizzata per ogni tipo di dispositivo. Poi puoi pubblicare lo stesso codice su tutti i dispositivi, tranne il livello di visualizzazione.
Il tuo progetto potrebbe avere la seguente struttura (ovviamente, puoi scegliere la struttura più adatta alla tua applicazione):
models/ (modelli condivisi) item.js item-collection.js
controllers/ (shared controllers) item-controller.js
versioni/ (elementi specifici del dispositivo) tablet/ desktop/ phone/ (codice specifico dello smartphone) style.css index.html views/ item.js item-list.js
Questo tipo di struttura ti consente di controllare completamente gli asset caricati da ogni versione, poiché disponi di HTML, CSS e JavaScript personalizzati per ogni dispositivo. Questo è molto potente e può portare al modo più snello e performante di sviluppare per il web cross-device, senza fare affidamento a trucchi come le immagini adattive.
Dopo aver eseguito lo strumento di compilazione preferito, tutti i file JavaScript e CSS vengono concatenati e minimizzati in singoli file per un caricamento più rapido. L'HTML di produzione avrà un aspetto simile al seguente (per smartphone, utilizzando device.js):
<!doctype html>
<head>
<title>Mobile Web Rocks! (Phone Edition)</title>
<!-- Every version of your webapp should include a list of all
versions. -->
<link rel="alternate" href="http://foo.com" id="desktop"
media="only screen and (touch-enabled: 0)">
<link rel="alternate" href="http://m.foo.com" id="phone"
media="only screen and (max-device-width: 650px)">
<link rel="alternate" href="http://tablet.foo.com" id="tablet"
media="only screen and (min-device-width: 650px)">
<!-- Viewport is very important, since it affects results of media
query matching. -->
<meta name="viewport" content="width=device-width">
<!-- Include device.js in each version for redirection. -->
<script src="device.js"></script>
<link rel="style" href="phone.min.css">
</head>
<body>
<script src="phone.min.js"></script>
</body>
Tieni presente che la media query (touch-enabled: 0) non è standard (è implementata solo in Firefox dietro un prefisso del fornitore moz), ma viene gestita correttamente (grazie a Modernizr.touch) da device.js.
Override della versione
Il rilevamento del dispositivo a volte può andare storto e in alcuni casi un utente potrebbe preferire visualizzare il layout del tablet sul proprio smartphone (magari sta usando un Galaxy Note), quindi è importante dare agli utenti la possibilità di scegliere quale versione del sito utilizzare se vogliono eseguire l'override manuale.
L'approccio abituale è quello di fornire un link alla versione desktop dalla versione mobile. L'implementazione è semplice, ma device.js supporta
questa funzionalità con il parametro GET device.
Conclusione
In sintesi, quando crei UI a pagina singola cross-device che non si adattano perfettamente al mondo del design responsivo, procedi nel seguente modo:
- Scegli un insieme di classi di dispositivi da supportare e i criteri in base ai quali classificare i dispositivi in classi.
- Crea la tua app MVC con una netta separazione delle responsabilità, dividendo le visualizzazioni dal resto del codice.
- Utilizza device.js per il rilevamento della classe di dispositivo lato client.
- Quando è tutto pronto, impacchetta lo script e i fogli di stile in uno per ogni classe di dispositivo.
- Se il rendimento del reindirizzamento lato client è un problema, abbandona device.js e passa al rilevamento UA lato server.