App Web a schermo intero

Uno dei primi problemi riscontrati durante la creazione di un'app Web mobile da zero è la quantità di spazio utilizzata dalla barra degli indirizzi del browser. Questo tutorial mostrerà come recuperare lo spazio reale dello schermo altrimenti perso nella barra degli indirizzi, tenendo conto delle variazioni di orientamento, dei problemi di altezza del contenuto e dei collegamenti interni dei documenti.

Modifiche successive alle tecniche e al software

Alcuni aspetti delle applicazioni o delle tecniche utilizzate in questo tutorial sono cambiati da quando è stato originariamente pubblicato. Questo potrebbe rendere un po 'difficile da seguire. Ti consigliamo di guardare questi tutorial più recenti sullo stesso argomento:

  • Mobiletuts + Categoria di app Web

Definire il problema

Uno degli aspetti più difficili della progettazione di dispositivi mobili è la quantità limitata di spazio disponibile sullo schermo. Le applicazioni Web mobili devono essere ottimizzate e intuitive per competere con le applicazioni native e la presenza dell'interfaccia utente del browser spesso sottrae solo l'esperienza dell'utente e l'estetica del sito nel suo complesso.

Ad esempio, considera la seguente schermata del sito Web mobile:

L'immagine sopra è stata scattata su un iPhone 4 con la barra degli indirizzi di Mobile Safari e la barra degli strumenti visualizzati.

Ora guarda lo stesso screenshot senza l'interfaccia utente del browser:

La versione per iPhone del sito ha guadagnato 60 pixel rimuovendo la barra degli indirizzi nella parte superiore e 44 pixel rimuovendo la barra dei pulsanti in basso per un guadagno totale di 104 pixel logici dello spazio verticale dello schermo (la quantità di spazio guadagnata sui dispositivi Android varia , ma il risultato è simile). Quando provi a costruire un'esperienza coinvolgente, è facile capire dagli screenshot che cosa può fare una grande differenza un cambiamento così piccolo.

Sfortunatamente, i principali browser Web mobili non hanno ancora fornito agli sviluppatori un metodo semplice e universale per attivare o disattivare semplicemente l'interfaccia utente del browser. Tuttavia, ci sono due approcci comuni per portare a termine il lavoro, ed entrambi saranno affrontati in questo tutorial.

L'approccio Meta Tag

Se la tua app Web ha come targeting solo iOS, quindi la soluzione ideale è impostare il seguente meta tag nel file porzione del tuo documento HTML:

 

In questo modo rimuoverà completamente sia la barra degli indirizzi del browser che la barra degli strumenti da Mobile Safari, come mostrato nella seconda schermata sopra.

Oltre al fatto che questo codice lo farà funziona in modo affidabile solo su dispositivi iOS, c'è un altro grosso problema con questo approccio: funzionerà solo dopo che l'utente ha aggiunto il sito Web alla schermata iniziale e quando l'utente avvia il sito indipendentemente da Mobile Safari.

Ho letto resoconti non confermati che l'approccio del metatag funzionerà davvero alcuni Anche i dispositivi Android, ma certamente non funzionano sul mio Nexus S e non sembrano affatto supportati ufficialmente da Android.

Questo è ovviamente meno che ideale. L'aggiunta di siti Web alla schermata iniziale di iOS è in qualche modo una funzione di iOS oscura che molti utenti non sanno nemmeno è possibile ed è improbabile che utilizzino mentre navigano casualmente sul Web.

Forse un giorno i produttori di browser si uniranno e forniranno un singolo meta tag multipiattaforma per un controllo preciso dell'interfaccia utente del browser senza ostacolare il normale flusso di applicazioni del browser Web (come sarebbe la vita se ciò accadesse effettivamente). Fino ad allora, dovremo prendere le cose nelle nostre mani alla vecchia maniera: usando JavaScript.

Contrappunto: Consentire agli sviluppatori di controllare la presenza della barra degli indirizzi e / o della barra delle schede garantisce libertà creativa agli sviluppatori a scapito della libertà dell'utente finale e dell'esperienza di navigazione complessiva. Senza uno schema UX coerente per tornare indietro o inserire un nuovo URL, gli utenti si confonderanno durante la navigazione e, in alcuni casi, non potranno lasciare il sito senza dover resettare completamente il browser.

Counter-contrappunto: Creazione di un nuovo pattern UX che consente agli sviluppatori di determinare la presenza o l'assenza di controlli del browser mantenendo allo stesso tempo il controllo dell'utente finale sulla navigazione (forse mediante una combinazione di un effetto di dissolvenza in apertura e il gesto di "doppio tocco" o forse di costringere le app a schermo intero ad avviarsi in una nuova finestra) potrebbe trovare un equilibrio tra entrambi gli interessi.

L'approccio JavaScript

Molti dei framework per app Web multipiattaforma ora disponibili si basano su ciò che è essenzialmente un hack JavaScript per avvicinarsi il più possibile a fornire un'esperienza a schermo intero. I seguenti framework includono tutti alcune varianti della soluzione JavaScript che illustrerò in questo tutorial:

  • iUI
  • SenchaTouch
  • jQuery Mobile

Per quelli di voi che vogliono solo il codice senza la narrativa:

Sto ospitando il codice sopra su GitHub: Gist, quindi sentiti libero di inserire, modificare o suggerire modifiche. Basta tenere a mente che questo è nel migliore dei casi un hack dipendente dal browser. Potrebbe cambiare in futuro. Potrebbe non coprire ogni caso limite. Non è stato testato su Blackberry e Windows Phone 7.

AGGIORNAMENTO 9/3/2011:
Grazie al feedback di John Boxall di seguito, ne ho aggiunto uno più condizionale nel listener di eventi "load". Il hideAddressBar () la funzione verrà ora richiamata solo se l'utente non ha iniziato a scorrere prima dell'attivazione dell'evento "load".

Per quelli di voi che vogliono imparare esattamente come e perché questo piccolo trucco funziona, continuate a leggere!

Avventurarsi nel buco del coniglio

In sostanza, il trucco equivale a ciò che può essere condensato in una singola riga di JavaScript:

 window.scrollTo (0, 1);

Il scrollTo la chiamata è un metodo di finestra oggetto browser con la seguente firma:

 scrollTo (x, y);

Il primo argomento controlla la distanza per scorrere la finestra sull'asse xe il secondo argomento controlla la distanza per scorrere la finestra sull'asse y.

Il concetto generale è che mentre non possiamo rimuovere tecnicamente i controlli del browser dal browser web, possiamo far scorrere il contenuto della vista verso il basso in modo da rimuovere la barra degli indirizzi dalla finestra.

Quindi, perché spostare solo l'asse Y 1 pixel? Non dovrebbe essere 60 pixel per l'iPhone? Questo è stato anche il mio pensiero iniziale. Tuttavia, la barra degli indirizzi non è tecnicamente parte della finestra del documento. Invece di far scorrere il contenuto verso il basso di 60 pixel, stiamo effettivamente sfruttando una particolarità di WebKit (bug?) Che rimuoverà automaticamente la barra degli indirizzi quando il scrollTo il metodo è chiamato. Nel mio test sono riuscito a ottenere l'effetto desiderato su iOS impostando il valore Y su qualsiasi numero intero, tra cui -10, 0, 1 o 60. Tuttavia, su Android, solo gli interi positivi hanno ottenuto l'effetto desiderato, quindi rendendo "1 "il miglior offset Y da utilizzare per l'hacking del browser.

Il prossimo passo è determinare quando chiamare il scrollTo metodo. Idealmente ciò dovrebbe accadere subito dopo il caricamento della pagina. Tutte le seguenti implementazioni hanno funzionato nei miei test e sono elencate in ordine di eleganza:

Aggiunta di un listener di eventi:

 window.addEventListener ("load", function () window.scrollTo (0, 1););

Aggiunta di un listener di eventi in linea:

 

All'interno di un embedded copione tag (per chi si sente ribelle):

   

Se provi tutti e tre questi esempi su Android, le cose dovrebbero funzionare bene (anche se il terzo esempio è particolarmente brutto). Tuttavia, se provi quanto sopra su iOS, non accadrà nulla.

Per motivi che non mi sono del tutto chiari, Mobile Safari su iOS non è in grado di applicare lo scroll hack con uno dei suddetti listener di eventi.

Per fare in modo che funzioni su iOS, è necessario produrre un leggero ritardo tra il momento in cui il listener di eventi si attiva e quando il scrollTo il metodo viene eseguito.

Questo può essere fatto facilmente con il setTimeout metodo come dimostrato:

 window.addEventListener ("load", function () setTimeout (function () window.scrollTo (0, 1);, 100);

La firma del metodo per setTimeout la funzione è:

 setTimeout (codice, millisecondi, [lang])

Quindi nel mio esempio ho fornito una funzione anonima contenente il scrollTo chiamata da eseguire dopo un ritardo di 100 millisecondi. Stranamente, quanto sopra ha funzionato ancora per me indipendentemente dal numero intero previsto per il ritardo di millisecondo. Ha funzionato con -100, 0 e 1 altrettanto bene di 100. Di conseguenza, il mio consiglio è di usare 0 per l'argomento dei millisecondi.

A questo punto, la nostra barra degli indirizzi che nasconde lo snippet JavaScript dovrebbe apparire come uno dei seguenti esempi:

Ascoltatore di eventi:

  Test a schermo intero 

Listener di eventi in linea:

 

Grande! Quindi ora possiamo passare alla costruzione di qualcosa di utile, giusto? Sfortunatamente no. Ci sono ancora diversi problemi specifici del browser che possono rovinare questo trucco.

Altezza del contenuto insufficiente

Cosa succede se il tuo contenuto non è abbastanza grande da riempire l'intero schermo? In tal caso, non avrai una barra di scorrimento verticale e il trucco mostrato sopra non funzionerà. Oltre a aggiungere semplicemente più contenuti alla tua pagina, ci sono almeno altri tre metodi meno restrittivi che puoi adottare per risolvere questo problema.

Opzione 1: imposta il Initial-Scale

Il primo approccio è modificare il iniziale scala della tua pagina web finché il tuo contenuto non riempie l'intera finestra. Puoi farlo con il seguente meta tag:

 

Avrai bisogno di giocare con il valore di scala iniziale fino a trovare la quantità di scala / zoom che corrisponde alle tue esigenze specifiche.

Opzione 2: imposta un'altezza minima

Il secondo approccio consiste nell'utilizzare un semplice attributo CSS. Puoi applicare un numero sufficientemente grande min-height valore per entrambi corpo tag o qualsiasi altro elemento a livello di blocco sulla tua pagina per tenere conto dello spazio bianco vuoto. Tuttavia, bisogna stare attenti qui per due motivi: il valore esatto del pixel richiesto dal min-height l'attributo varierà in base al iniziale scala (cioè zoom) della pagina e il valore cambierà se l'utente passa dalla modalità verticale alla modalità orizzontale o viceversa. Di seguito è riportata la sintassi di base per l'impostazione dell'attributo min-height sul tag body:

 body min-height: 900px; 

Ancora: il valore effettivo del pixel utilizzato dipende dalla scala / zoom iniziale del tuo sito. Potrebbe essere necessario andare piuttosto alto o piuttosto basso.

Opzione 3: imposta dinamicamente l'altezza con JavaScript

Il terzo approccio consiste nel controllare dinamicamente il document.height proprietà contro il window.outerHeight proprietà e quindi aumentare dinamicamente la dimensione di document.height quando necessario.

A seguito di snippet di codice JavaScript è una soluzione non quadro a questo problema:

 

Alle righe 5 sopra, ho aggiunto una quantità apparentemente arbitraria di padding (+50). Questo è stato necessario affinché l'effetto funzioni sia su iOS che su Android. Ho anche dovuto riposizionare la chiamata a setTimeout poiché iOS non produrrebbe lo scorrimento automatico subito dopo l'impostazione document.body.style.height. Ciò che ho trovato particolarmente strano era che non solo avevo bisogno di riposizionare il setTimeout call, ma per iOS ho anche dovuto aggiungere un ritardo apparentemente arbitrario di +50 se avessi appena cambiato l'altezza del documento. Questo non era il caso inizialmente (quando si usa il caricare ascoltatore senza impostare un nuovo valore per l'altezza del documento).

Collegamenti interni / di ancoraggio

Variazioni sulla suddetta modifica del browser sono già ampiamente implementate sul web. Tuttavia, vi è almeno un caso d'uso in cui forzare il browser a scorrere fino a 0,1 è esattamente l'approccio sbagliato: i visitatori arrivano al tuo sito tramite un collegamento di ancoraggio (a.k.a. interno). Per accogliere questo caso limite è necessario chiamare scrollTo (0, 1) se il tag hash non è presente nell'URL. Per implementare questo approccio, tutto ciò che dobbiamo fare è verificare la presenza di un valore in window.location.hash e poi avvolgere il nostro caricare ascoltatore di eventi all'interno di quel condizionale. Farlo ci lascia con qualcosa come il seguente:

 if (! window.location.hash) window.addEventListener ("load", function () if (document.height <= window.outerHeight + 10)  document.body.style.height = (window.outerHeight + 50) +'px'; setTimeout( function() window.scrollTo(0, 1); , 50 );  else  setTimeout( function() window.scrollTo(0, 1); , 0 );   ); 

Modifiche all'orientamento del dispositivo

Un altro problema che potresti incontrare riguarda le modifiche all'orientamento del dispositivo. Su iOS, quando un utente fa ruotare il telefono dalla modalità verticale alla modalità orizzontale, l'offset di scorrimento non verrà modificato automaticamente (Android non sembra soffrire di questo problema). Ciò significa che il tuo utente verrà lasciato da qualche parte più in basso rispetto alla destinazione.

La correzione per questo è impostare un listener di eventi su window.onorientationchange essere avvisati quando l'orientamento cambia e quindi eseguire il window.scrollTo (0, 1) chiama di nuovo dopo che si verifica il cambiamento.

Questo sembra un buon momento per iniziare a rifattorizzare il codice suddividendo il codice responsabile per nascondere effettivamente la barra degli indirizzi in una funzione indipendente. Dopo averlo fatto, ci rimane il seguente:

 function hideAddressBar () if (! window.location.hash) if (document.height <= window.outerHeight + 10)  document.body.style.height = (window.outerHeight + 50) +'px'; setTimeout( function() window.scrollTo(0, 1); , 50 );  else  setTimeout( function() window.scrollTo(0, 1); , 0 );    window.addEventListener("load", hideAddressBar ); window.addEventListener("orientationchange", hideAddressBar );

La soluzione di cui sopra sembra funzionare perfettamente per me sia su Android che su iOS, ma c'è un altro problema che può o non può essere rilevante per il tuo progetto: cosa succede se l'utente ha fatto scorrere in modo significativo la pagina prima di cambiare l'orientamento del dispositivo? In tal caso, reimpostare il display su 0, 1 causerebbe la perdita della posizione dell'utente nel documento. Contabilità per questo è altamente specifica di implementazione, ma il succo è quello di impostare semplicemente una soglia dell'asse y e quindi solo ripristinare l'offset di scorrimento su 0, 1 se l'utente non ha ancora scostato oltre tale soglia.

Blocco della barra degli indirizzi sullo schermo

Alcuni framework, come SenchaTouch, bloccano effettivamente la barra degli indirizzi sullo schermo impedendo all'utente di scorrere oltre una determinata soglia dell'asse y. Questo è certamente possibile, ma non discuterò su come farlo in quanto trovo questa soluzione un problema di usabilità significativo, in particolare su Android. Tuttavia, se sei determinato a raggiungere questo effetto, probabilmente dovrai sperimentare con window.pageYOffset attributo.

Che dire della barra dei pulsanti su iOS?

Per quanto ne so, al momento non esiste una soluzione per rimuovere la barra degli strumenti / barra dei pulsanti su iOS dalla parte inferiore di Mobile Safari con JavaScript da solo. L'unico modo in cui sono consapevole di ottenere questo effetto è l'approccio del metatag spiegato all'inizio di questo tutorial. Correggimi se sbaglio!

Rendendolo condizionale

Una considerazione con l'approccio sopra non ancora discusso è come gestire gli utenti che visitano da un browser web non mobile o non supportato. Esistono diversi metodi per determinare quale browser sta attualmente accedendo al tuo sito. Se si sta lavorando con un linguaggio di scripting sul lato server, è possibile determinare se l'utente si trova su un dispositivo mobile nel momento in cui viene generata la pagina e fornire solo tale modifica, se necessario. Forse un approccio più robusto sarebbe quello di eseguire il test dinamicamente con JavaScript. L'applicazione di questa considerazione va oltre lo scopo di questo tutorial, ma per favore lasciate i vostri suggerimenti nei commenti.

Caveat Emptor!

Gli hack del browser come quello che ho descritto per nascondere la barra degli indirizzi sfidano le best practice. L'implementazione che ho spiegato in questo tutorial è stata testata su un Android Nexus S, iPhone 3GS e un iPhone 4, ma è del tutto possibile che mi sia sfuggito un caso limite. Inoltre, non sono affatto certo che l'implementazione mostrata continuerà a funzionare così come è nel futuro, motivo per cui sono rimasto piuttosto sorpreso nel trovare così tanti framework web primari (ad esempio iUI, jQuery Mobile, SenchaTouch) e prominenti siti Web (ad esempio Gmail, Yahoo, Apple) basandosi su alcune varianti personalizzate di questo hack. La ragione, penso, è semplice: al momento non esiste una soluzione migliore, non javascript.

Incartare

Avevo tre intenti principali nello scrivere un tutorial così approfondito su quello che potrebbe sembrare un problema banale.

Innanzitutto, volevo fornire un puro snippet di JavaScript per ottenere questo effetto più robusto rispetto alla maggior parte degli altri che ho incontrato. Spero di aver raggiunto questo obiettivo accettando cambiamenti di orientamento, collegamenti di ancoraggio e problemi di altezza del contenuto.

In secondo luogo, volevo dissipare un po 'della magia dietro a come framework come SenchaTouch o iUI hanno reso possibile questo effetto. Quando ho deciso di usare SenchaTouch per un progetto freelance qualche tempo fa, la "magia" del framework per realizzare app sullo schermo era uno degli effetti UX primari che mi piacevano. È importante rendersi conto che questo stesso effetto può essere facilmente implementato in JS puro indipendentemente dal fatto che tu scelga o meno di utilizzare un framework JavaScript nel tuo progetto.

Infine, il motivo principale per cui volevo affrontare questo problema in modo così dettagliato è quello di sensibilizzare sul modo in cui questo approccio è veramente volubile. Nonostante il fatto che le varianti di questo trucco siano state ampiamente adottate, ritengo che sia nel migliore dei casi un inelegant kludge e nel peggiore un hack dipendente dal browser che potrebbe continuare a funzionare in futuro. Vorrei esortare coloro che operano nel settore dei browser e la comunità di sviluppo web / mobile nel suo complesso a spingere per un approccio indipendente basato su standard e JavaScript per affrontare questa considerazione UX. Penso che il metodo del meta-tag che Apple ha implementato sia un grande passo nella giusta direzione, ma, come accennato in precedenza, non soddisfa abbastanza le esigenze della comunità di sviluppo.

La vera domanda è: cosa ne pensi? Parliamone nella sezione commenti qui sotto.

Migliora questo codice

Non ho dubbi che alcuni dei nostri lettori potrebbero essere in grado di migliorare il codice che ho fornito in questo tutorial. Se vedi qualcosa in questo post che potrebbe essere ottimizzato o migliorato, lascia il tuo feedback qui sotto! Puoi anche raggiungermi tramite Twitter (@markhammonds), anche se a volte mi ci vuole un po 'per rispondere a Tweets o DM. Il modo migliore per raggiungermi è nei commenti qui sotto o con il modulo di contatto su Mobileuts +. Se accetto uno dei tuoi suggerimenti per il miglioramento, aggiornerò questo post e citerò il tuo nome o la tua gestione!

Riferimenti

Non voglio prendere la parola per nessuno dei precedenti?

Dai uno sguardo alle seguenti risorse che ho trovato durante la ricerca di questo post:

  • Configurazione di applicazioni Web, Safari Developer Library
  • "Mobbing" del tuo sito HTML5, Eric Bidelman
  • Nascondi la barra degli indirizzi all'interno delle applicazioni Web mobili, David Walsh
  • iPhone WebApps 101: Avvio di Safari fuori strada, Niels Leenheer