Un approccio non adattabile alla creazione di web app cross-device

Boris Smus
Boris Smus

Le query supporti sono fantastiche, ma…

Le query sui media sono fantastiche, una manna dal cielo per gli sviluppatori di siti web che vogliono apportare piccole modifiche ai propri 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 iniziare a leggere questo articolo, scopri di più sul design adattabile e dai un'occhiata ad alcuni esempi di utilizzo delle query supporti qui: mediaqueri.es.

Come sottolineato da Brad Frost in un articolo precedente, cambiare l'aspetto è solo uno dei tanti aspetti da considerare quando si sviluppano siti per il web mobile. Se l'unica cosa che fai quando crei il tuo sito web mobile è personalizzare il layout con le query sui media, si verifica la seguente situazione:

  • Tutti i dispositivi ricevono gli stessi JavaScript, CSS e asset (immagini, video), con 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 complicati.
  • Poca flessibilità per specificare interazioni personalizzate adattate a ogni dispositivo.

Le web app richiedono più di query sui contenuti multimediali

Non fraintendermi. Non odio il design responsive tramite query sui media e ritengo che abbia un ruolo importante. Inoltre, alcuni dei problemi sopra menzionati possono essere risolti con approcci come le immagini responsive, il caricamento di script dinamici e così via. Tuttavia, a un certo punto potresti trovarti a apportare troppi aggiustamenti incrementali e potrebbe essere meglio pubblicare versioni diverse.

Man mano che le UI che crei diventano più complesse e tendi a utilizzare web app a pagina singola, dovrai fare di più per personalizzare le UI per ogni tipo di dispositivo. Questo articolo ti insegnerà come eseguire queste personalizzazioni con il minimo sforzo. L'approccio generale consiste nel classificare il dispositivo del visitatore nella classe di dispositivo corretta e pubblicare la versione appropriata per quel dispositivo, massimizzando al contempo il riutilizzo del codice tra le versioni.

Quali classi di dispositivi scegli come target?

Esistono tantissimi dispositivi connessi a internet e quasi tutti hanno un browser. La complicazione sta nella loro diversità: laptop Mac, stazioni di lavoro Windows, iPhone, iPad, smartphone Android con input tocco, rotelle di scorrimento, tastiere, input vocale, dispositivi con sensibilità alla pressione, smartwatch, tostapane e frigoriferi e molti altri. Alcuni di questi dispositivi sono onnipresenti, mentre altri sono molto rari.

Una serie di dispositivi.
Una serie di dispositivi (source).

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 di computer 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 inserimento.

Esistono due estremi dello spettro di approcci:

  1. Crea una versione che funzioni su tutti i dispositivi. Di conseguenza, l'esperienza utente ne risentirà, poiché i dispositivi diversi hanno considerazioni di progettazione diverse.

  2. Crea una versione per ogni dispositivo che vuoi supportare. Ci vorrà moltissimo tempo, perché creerai troppe versioni della tua applicazione. Inoltre, quando arriverà il prossimo nuovo smartphone (cosa che accade all'incirca ogni settimana), dovrai 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 gestire.

Può essere una buona idea creare una versione separata per ogni classe di dispositivi che scegli per motivi di rendimento o se le versioni che vuoi pubblicare per classi di dispositivi diverse variano notevolmente. In caso contrario, il responsive web design è un approccio perfettamente ragionevole.

Una potenziale soluzione

Ecco un 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 compatibili con il web più diffusi oggi esistenti.

  1. Schermi piccoli + tocco (soprattutto smartphone)
  2. Schermi grandi + tocco (principalmente tablet)
  3. schermi grandi + tastiera/mouse (principalmente computer/laptop)

Questa è solo una delle tante possibili suddivisioni, ma una che ha molto senso al momento in cui scriviamo. Nell'elenco sopra riportato mancano i dispositivi mobili senza touchscreen (ad es. cellulari, alcuni lettori di ebook dedicati). Tuttavia, la maggior parte di questi ha installato software di navigazione da tastiera o screen reader, che funzioneranno perfettamente se crei il tuo sito tenendo presente l'accessibilità.

Esempi di app web 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 in merito includono sia il rendimento (recupero degli asset, rendering delle pagine) sia un'esperienza utente più generale.

Nel mondo delle app native, molti sviluppatori scelgono di personalizzare la loro 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'uso con due mani e la rotazione orizzontale, mentre la versione per smartphone è pensata per l'interazione con una sola mano e la rotazione verticale. Molte altre applicazioni per iOS forniscono anche versioni per smartphone e tablet molto diverse, come Things (lista di cose da fare) e Showyou (video social), mostrate di seguito:

Personalizzazione significativa dell'interfaccia utente per smartphone e tablet.
Personalizzazione significativa dell'interfaccia utente per smartphone e tablet.

Approccio 1: rilevamento lato server

Sul server, abbiamo una conoscenza 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. In effetti, i progetti DeviceAtlas e WURFL lo fanno già (e forniscono molte altre informazioni sul dispositivo).

Purtroppo, ognuna di queste soluzioni presenta delle sfide. WURFL è molto grande, contiene 20 MB di XML e potrebbe comportare un sovraccarico lato server significativo per ogni richiesta. Alcuni progetti suddividono il codice XML per motivi di rendimento. DeviceAtlas non è open source e richiede una licenza a pagamento per l'utilizzo.

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 2: rilevamento lato client

Possiamo scoprire molto sul browser e sul dispositivo dell'utente utilizzando il rilevamento delle funzionalità. Le cose principali che dobbiamo stabilire sono se il dispositivo ha funzionalità touch e se lo schermo è grande o piccolo.

Dobbiamo tracciare una linea da qualche parte per distinguere i dispositivi touch piccoli e grandi. E per i casi limite come il Galaxy Note da 5"? La seguente illustrazione 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 disponibile con una densità raddoppiata. Anche se la densità di pixel può essere raddoppiata, il CSS riporta comunque le stesse dimensioni.

Una breve nota sui pixel in CSS: i pixel CSS sul web mobile non sono uguali ai pixel dello schermo. I dispositivi iOS Retina hanno introdotto la pratica di raddoppiare la densità di pixel (ad es. iPhone 3GS e 4, iPad 2 e 3). Le UA Safari mobile retina continuano a segnalare la stessa larghezza del dispositivo per evitare di interrompere il web. Come altri dispositivi (ad es. Android) ricevono display con risoluzioni più elevate, utilizzano lo stesso trucco per la larghezza del dispositivo.

Risoluzione del dispositivo (in pixel).
Risoluzione del dispositivo (in pixel).

A complicare questa decisione, però, è l'importanza di prendere in considerazione sia la modalità verticale sia 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, a seguito dell'applicazione degli schemi di sovrapposizione verticale e orizzontale (e del completamento del quadrato):

Risoluzione verticale + orizzontale (in pixel)
Risoluzione verticale e orizzontale (in pixel)

Impostando la soglia su 650px, classifichiamo iPhone e Galaxy Nexus come "piccoli dispositivi touch" e iPad e Galaxy Tab come "tablet". In questo caso, il Galaxy Note androgino viene classificato come "smartphone" e riceverà 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 regole euristiche e le associ ai navigator.userAgent del tuo utente. Il pseudocodice ha il seguente aspetto:

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 a disposizione:

  1. Reindirizza a un URL specifico per tipo di dispositivo che contiene la versione per questo tipo di dispositivo.
  2. Carica dinamicamente gli asset specifici per tipo di dispositivo.

Il primo approccio è semplice e richiede un reindirizzamento comewindow.location.href = '/tablet'. Tuttavia, ora alla posizione verranno aggiunte queste 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. È necessario un meccanismo per caricare dinamicamente CSS e JS e, a seconda del browser, potresti non essere in grado di eseguire operazioni come personalizzare <meta viewport>. Inoltre, poiché non è presente alcun reindirizzamento, non puoi fare altro che utilizzare il codice 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:

Client Pro:

  • Più adatto al futuro perché si basa sulle dimensioni/funzionalità dello schermo anziché su UA.
  • Non è necessario aggiornare costantemente l'elenco UA.

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 ritieni che il reindirizzamento lato client sia un svantaggio significativo per le prestazioni, puoi rimuovere facilmente lo script device.js e implementare il rilevamento UA sul server.

Introduzione a device.js

Device.js è un punto di partenza per il rilevamento semantico dei dispositivi basato su query multimediali senza bisogno di una configurazione lato server speciale, il che consente di risparmiare tempo e fatica per l'analisi della stringa dello user agent.

L'idea è che tu fornisca un markup adatto ai motori di ricerca (link rel=alternate) nella parte superiore del tuo <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 dell'UA lato server e gestire autonomamente il reindirizzamento della versione oppure utilizzare lo script device.js per eseguire il reindirizzamento lato client in base alle funzionalità.

Per ulteriori informazioni, consulta la pagina del progetto device.js e anche un'applicazione falsa che utilizza device.js per il reindirizzamento lato client.

Suggerimento: MVC con visualizzazioni specifiche per fattore di forma

A questo punto probabilmente penserai che ti sto dicendo di creare tre app completamente separate, una per ogni tipo di dispositivo. No! La condivisione del codice è la chiave.

Spero che tu stia utilizzando un framework simile a MVC, come Backbone, Ember e così via. In questo caso, hai dimestichezza con il principio della separazione delle preoccupazioni, in particolare che l'interfaccia utente (livello di visualizzazione) debba essere disaccoppiata dalla logica (livello del modello). Se non hai dimestichezza con questo argomento, consulta alcune di queste risorse su MVC e MVC in JavaScript per iniziare.

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. In questo modo puoi pubblicare lo stesso codice su tutti i dispositivi, tranne il livello di visualizzazione.

MVC cross-device.
MVC cross-device
.

Il progetto potrebbe avere la seguente struttura (ovviamente, sei libero di scegliere la struttura più adatta in base alla tua applicazione):

models/ (modelli condivisi) item.js item-collection.js

controllers/ (controller condivisi) item-controller.js

versions/ (contenuti specifici per il dispositivo) tablet/ desktop/ phone/ (codice specifico per il telefono) 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é hai HTML, CSS e JavaScript personalizzati per ogni dispositivo. Questa funzionalità è molto potente e può portare al modo più snello e performante di sviluppare per il web cross-device, senza fare affidamento su trucchi come le immagini adattabili.

Dopo aver eseguito lo strumento di compilazione che preferisci, concatena e minimizza tutto il codice JavaScript e CSS in singoli file per velocizzare il caricamento. Il codice HTML di produzione avrà il seguente aspetto (per il telefono, 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 query sui media (touch-enabled: 0) non è standard (implementata solo in Firefox dietro un prefisso del fornitore (touch-enabled: 0)), ma viene gestita correttamente (grazie a Modernizr.touch) da device.js.moz

Sostituzione della versione

Il rilevamento del dispositivo a volte può non andare a buon fine e, in alcuni casi, un utente potrebbe preferire visualizzare il layout del tablet sul proprio smartphone (ad esempio se utilizza un Galaxy Note). Pertanto, è importante offrire agli utenti la possibilità di scegliere la versione del sito da utilizzare se vogliono eseguire l'override manuale.

L'approccio usuale è fornire un link alla versione desktop dalla versione mobile. È abbastanza facile da implementare, 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 inseriscono perfettamente nel mondo del responsive design:

  1. Scegli un insieme di classi di dispositivi da supportare e i criteri in base ai quali classificare i dispositivi in classi.
  2. Crea la tua app MVC con una forte separazione degli aspetti, dividendo le visualizzazioni dal resto della base di codice.
  3. Utilizza device.js per rilevare la classe del dispositivo lato client.
  4. Al termine, raggruppa lo script e i fogli di stile in uno per ogni classe di dispositivo.
  5. Se il rendimento del reindirizzamento lato client è un problema, abbandona device.js e passa al rilevamento UA lato server.