Aplicaciones web de pantalla completa

Uno de los primeros problemas encontrados al crear una aplicación web móvil desde cero es la cantidad de espacio que consume la barra de direcciones del navegador. Este tutorial le mostrará cómo reclamar el estado real de la pantalla que de lo contrario se perdería en la barra de direcciones al tiempo que contabiliza los cambios de orientación, los problemas de altura del contenido y los enlaces de documentos internos..

Cambios posteriores a las técnicas y software

Ciertos aspectos de las aplicaciones o técnicas utilizadas en este tutorial han cambiado desde que se publicó originalmente. Esto podría hacer que sea un poco difícil de seguir. Recomendamos ver estos tutoriales más recientes sobre el mismo tema:

  • Mobiletuts + Categoría de aplicaciones web

Definiendo el problema

Uno de los aspectos más difíciles de diseñar para dispositivos móviles es la cantidad limitada de espacio de pantalla disponible. Las aplicaciones web móviles deben ser simplificadas e intuitivas para competir con las aplicaciones nativas, y la presencia de la interfaz de usuario del navegador a menudo solo resta de la experiencia del usuario y la estética del sitio en general..

Por ejemplo, considere la siguiente captura de pantalla del sitio web móvil:

La captura de pantalla anterior se tomó en un iPhone 4 con la barra de direcciones de Mobile Safari y la barra de herramientas mostradas.

Ahora eche un vistazo a la misma captura de pantalla sin la interfaz de usuario del navegador:

La versión para iPhone del sitio ganó 60 píxeles al eliminar la barra de direcciones en la parte superior y 44 píxeles al eliminar la barra de botones en la parte inferior para obtener una ganancia total de 104 píxeles lógicos de espacio vertical de pantalla (la cantidad de espacio ganado en los dispositivos Android varía , pero el resultado es similar). Cuando se trata de crear una experiencia inmersiva, es fácil distinguir las capturas de pantalla que se encuentran sobre la gran diferencia que un cambio tan pequeño puede hacer..

Desafortunadamente, los principales navegadores web móviles todavía no han proporcionado a los desarrolladores un método fácil y universal para simplemente activar o desactivar la interfaz de usuario del navegador. Sin embargo, hay dos enfoques comunes para hacer el trabajo, y ambos serán abordados en este tutorial..

El enfoque de etiqueta Meta

Si su aplicación web solo está orientada a iOS, entonces la solución ideal es establecer la siguiente metaetiqueta en el parte de su documento HTML:

 

Si lo hace, eliminará completamente tanto la barra de direcciones del navegador como la barra de herramientas de Mobile Safari, como se muestra en la segunda captura de pantalla anterior.

Además del hecho de que este código solo funciona de forma fiable en dispositivos iOS, Hay otro problema importante con este enfoque: solo funcionará después de que el usuario haya agregado el sitio web a la pantalla de inicio y cuando el usuario inicie el sitio independientemente de Mobile Safari.

He leído informes no confirmados de que el enfoque de etiqueta meta realmente funcionará en algunos Los dispositivos Android también, pero ciertamente no funcionan en mi Nexus S y parece que no son oficialmente compatibles con Android.

Esto obviamente es menos que ideal. Agregar sitios web a la pantalla de inicio de iOS es algo así como una característica oscura de iOS que muchos usuarios ni siquiera saben que es posible y es poco probable que utilicen mientras navegan casualmente por la web.

Quizás algún día los proveedores de navegadores se unirán y suministrarán una etiqueta meta multiplataforma para un control preciso sobre la interfaz de usuario del navegador sin obstruir el flujo normal de la aplicación del navegador web (cómo sería la vida si esto realmente ocurriera). Hasta entonces, tendremos que tomar las cosas en nuestras manos de la manera tradicional: usando JavaScript.

Contrapunto: Permitir que los desarrolladores controlen la presencia de la barra de direcciones y / o la barra de pestañas otorga libertad creativa a los desarrolladores a expensas de la libertad del usuario final y la experiencia de navegación general. Sin un patrón UX consistente para navegar hacia atrás o ingresar una nueva URL, los usuarios se confundirán mientras navegan y en algunos casos no podrán abandonar el sitio sin reiniciar completamente el navegador.

Contrapunto: Creando un nuevo patrón de UX que permite a los desarrolladores determinar la presencia o ausencia de controles del navegador y, al mismo tiempo, mantener el control del usuario final sobre la navegación (tal vez por una combinación de un efecto de desaparición gradual y el gesto de "doble toque" o quizás forzar aplicaciones de pantalla completa para iniciarse en una nueva ventana) podría lograr un equilibrio entre ambos intereses.

El enfoque de JavaScript

Muchos de los marcos de aplicaciones web multiplataforma ahora disponibles confían en lo que esencialmente es un hack de JavaScript para acercarse lo más posible a una experiencia de pantalla completa. Los siguientes marcos, todos incluyen alguna variación de la solución JavaScript que demostraré en este tutorial:

  • iUI
  • SenchaTouch
  • jQuery Mobile

Para aquellos de ustedes que solo quieren el código sin la narrativa:

Estoy alojando el código anterior en GitHub: Gist, así que siéntase libre de bifurcar, modificar o sugerir cambios. Solo ten en cuenta que esto es, en el mejor de los casos, un hack que depende del navegador. Puede cambiar en el futuro. Puede que no cubra todos los casos de borde. No está probado en Blackberry y Windows Phone 7.

ACTUALIZACIÓN 9/3/2011:
Gracias a los comentarios de John Boxall a continuación, agregué un condicional más en el detector de eventos "cargar". los hideAddressBar () ahora solo se llamará a la función si el usuario no ha comenzado a desplazarse antes de que se active el evento de "carga".

Para aquellos de ustedes que quieran aprender exactamente cómo y por qué funciona este pequeño truco, siga leyendo.!

Aventurarse por el agujero del conejo

En esencia, el truco equivale a lo que se puede condensar en una sola línea de JavaScript:

 window.scrollTo (0, 1);

los scrollTo llamar es un método de ventana objeto del navegador con la siguiente firma:

 scrollTo (x, y);

El primer argumento controla la distancia para desplazar la ventana en el eje x y el segundo argumento controla la distancia para desplazar la ventana en el eje y.

El concepto general es que, si bien técnicamente no podemos eliminar los controles del navegador del navegador web, podemos desplazar el contenido de la ventana gráfica hacia abajo para eliminar la barra de direcciones de la ventana.

Entonces, ¿por qué solo mover el píxel del eje Y 1? ¿No debería ser de 60 píxeles para el iPhone? Ese fue mi pensamiento inicial también. Sin embargo, la barra de direcciones no es técnicamente parte de la ventana gráfica. En lugar de desplazar el contenido a 60 píxeles, estamos aprovechando una peculiaridad de WebKit (¿error?) Que eliminará automáticamente la barra de direcciones cuando scrollTo se llama metodo En mis pruebas pude lograr el efecto deseado en iOS configurando el valor de Y en cualquier entero, incluido -10, 0, 1 o 60. Sin embargo, en Android, solo los enteros positivos lograron el efecto deseado, por lo que hice "1 "La mejor compensación Y para usar para el navegador hack.

El siguiente paso es determinar cuándo llamar al scrollTo método. Idealmente, esto debería suceder justo después de que se cargue la página. Todas las siguientes implementaciones funcionaron en mis pruebas y se enumeran en orden de elegancia:

Añadiendo un detector de eventos:

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

Agregar un detector de eventos en línea:

 

Dentro de un incrustado guión etiqueta (para los que se sienten rebeldes):

   

Si prueba las tres de estas muestras en Android, las cosas deberían funcionar a la perfección (aunque el tercer ejemplo es especialmente feo). Sin embargo, si intentas lo anterior en iOS, no pasará nada..

Por razones que no me son del todo claras, Mobile Safari en iOS es incapaz de aplicar el pirateo de desplazamiento solo con cualquiera de los oyentes de eventos anteriores.

Para que esto funcione en iOS, debe generar un ligero retraso entre el momento en que se activa el detector de eventos y el momento en que scrollTo método se ejecuta.

Esto se puede hacer fácilmente con el setTimeout método como se demuestra:

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

La firma del método para el setTimeout la función es:

 setTimeout (código, milisegundos, [lang])

Así que en mi ejemplo proporcioné una función anónima que contiene la scrollTo Llamar para ser ejecutado después de un retraso de 100 milisegundos. Por extraño que parezca, lo anterior aún funcionó para mí independientemente del número entero proporcionado para el retraso de milisegundos. Funcionó con -100, 0 y 1, así como con 100. En consecuencia, mi recomendación es usar 0 para el argumento de los milisegundos.

En este punto, nuestra barra de direcciones que oculta el fragmento de código de JavaScript debería ser similar a uno de los siguientes ejemplos:

Oyente del evento:

  Prueba de pantalla completa 

Detector de eventos en línea:

 

¡Genial! Así que ahora podemos pasar a construir algo realmente útil, ¿verdad? Lamentablemente no. Todavía hay varios problemas específicos del navegador que pueden desbaratar este hack.

Altura de contenido insuficiente

¿Qué pasa si tu contenido no es lo suficientemente grande como para llenar toda la pantalla? En ese caso, no tendrá una barra de desplazamiento vertical, y el truco demostrado anteriormente no funcionará. Además de simplemente agregar más contenido a su página, existen al menos otros tres métodos menos restrictivos que puede tomar para enfrentar este problema..

Opción 1: establecer el Escala inicial

El primer enfoque es modificar el escala inicial de su página web hasta que su contenido llene toda la ventana gráfica. Puedes hacer esto con la siguiente etiqueta meta:

 

Tendrá que jugar con el valor de la escala inicial hasta que encuentre la cantidad de escala / zoom que coincida con sus necesidades específicas.

Opción 2: Establecer una altura mínima

El segundo enfoque es utilizar un atributo CSS simple. Se puede aplicar una suficientemente grande. min-height valor a cualquiera de los cuerpo etiqueta o cualquier otro elemento de nivel de bloque en su página para tener en cuenta el espacio en blanco vacío. Sin embargo, debe tener cuidado aquí por dos razones: el valor de píxel exacto que necesita el min-height atributo variará dependiendo de la escala inicial (es decir, el zoom) de la página y el valor cambiará si el usuario gira de modo vertical a horizontal o viceversa. La sintaxis básica para establecer el atributo de altura mínima en la etiqueta del cuerpo se muestra a continuación:

 cuerpo min-height: 900px; 

De nuevo: el valor real de píxeles utilizado depende de la escala inicial / zoom de su sitio. Puede que tengas que ir bastante alto o bastante bajo.

Opción 3: establecer dinámicamente la altura con JavaScript

El tercer enfoque es comprobar dinámicamente el document.height propiedad contra la window.outerHeight propiedad y luego aumentar dinámicamente el tamaño de document.height cuando sea necesario.

Para seguir el fragmento de código JavaScript es una solución que no es de marco para este problema:

 

En las líneas 5 anteriores, he agregado una cantidad aparentemente arbitraria de relleno (+50). Esto fue necesario para que el efecto funcione tanto en iOS como en Android. También he tenido que reposicionar la llamada a setTimeout como iOS no produciría el desplazamiento automático inmediatamente después de configurar document.body.style.height. Lo que me pareció especialmente extraño fue que no solo tenía que reposicionar el setTimeout llamada, pero para iOS también tuve que agregar un retraso aparentemente arbitrario de +50 si hubiera cambiado la altura del documento. Este no fue el caso inicialmente (al usar el carga escucha sin establecer un nuevo valor para la altura del documento).

Enlaces internos / de anclaje

Las variaciones en el hack del navegador anterior ya están ampliamente implementadas en la web. Sin embargo, hay al menos un caso de uso en el que obligar al navegador a desplazarse a 0,1 es exactamente el enfoque incorrecto: los visitantes que llegan a su sitio a través de un enlace ancla (a.k.a. interno). Para acomodar este caso de borde solo necesita llamar scrollTo (0, 1) si la etiqueta hash no está presente en la URL. Para implementar este enfoque, todo lo que debemos hacer es verificar la presencia de un valor en window.location.hash y luego envolver nuestro carga oyente del evento dentro de ese condicional. Si lo hace, nos deja con algo como lo siguiente:

 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 );   ); 

Cambios en la orientación del dispositivo

Otro problema que puede encontrar tiene que ver con los cambios de orientación del dispositivo. En iOS, cuando un usuario gira el teléfono del modo vertical al modo horizontal, el desplazamiento de desplazamiento no se cambiará automáticamente (parece que Android no sufre este problema). Esto significa que su usuario quedará en algún lugar más abajo de la página de lo que está previsto.

La solución para esto es establecer un detector de eventos en ventana. cambio de orientación para ser notificado cuando cambie la orientación, y luego ejecutar la window.scrollTo (0, 1) llamar de nuevo después de que ocurra el cambio.

Este parece ser un buen momento para comenzar a refactorizar el código dividiendo el código responsable de ocultar la barra de direcciones en una función independiente. Después de hacerlo, nos quedamos con lo siguiente:

 función 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 solución anterior parece funcionar muy bien para mí tanto en Android como en iOS, pero hay un problema más que puede o no ser relevante para su proyecto: ¿qué sucede si el usuario se ha desplazado significativamente por la página antes de cambiar la orientación del dispositivo? En ese caso, restablecer la pantalla a 0, 1 causaría que el usuario pierda su lugar en el documento. Considerar esto es altamente específico de la implementación, pero lo esencial es establecer simplemente un umbral del eje y y luego solo restablecer el desplazamiento de desplazamiento a 0, 1 si el usuario no se ha desplazado más allá de ese umbral.

Bloqueo de la barra de direcciones fuera de la pantalla

Algunos marcos, como SenchaTouch, en realidad bloquearán la barra de direcciones de la pantalla impidiendo que el usuario se desplace más allá de un umbral dado del eje y. Esto es ciertamente posible, pero no discutiré cómo hacerlo aquí, ya que encuentro que esta solución es un problema importante de usabilidad, especialmente en Android. Sin embargo, si está decidido a lograr este efecto, es probable que tenga que experimentar con el window.pageYOffset atributo.

¿Qué pasa con la barra de botones en iOS??

Que yo sepa, actualmente no hay una solución para eliminar la barra de herramientas / barra de botones en iOS de la parte inferior de Mobile Safari con solo JavaScript. La única forma que conozco para lograr este efecto es el enfoque de metaetiqueta que se explica al comienzo de este tutorial. Corrígeme si me equivoco!

Haciéndolo Condicional

Una consideración con el enfoque anterior no discutido aún es cómo manejar a los usuarios que visitan desde un navegador web no móvil o no compatible. Existen varios métodos diferentes para determinar qué navegador está accediendo actualmente a su sitio. Si está trabajando con un lenguaje de script del lado del servidor, es posible que desee determinar si el usuario está en un dispositivo móvil en el momento en que se genera la página y solo proporcionar este truco cuando sea necesario. Quizás un enfoque más robusto sería hacer las pruebas dinámicamente con JavaScript. Aplicar esta consideración está más allá del alcance de este tutorial, pero deje sus sugerencias en los comentarios.

Advertencia emptor!

Hacks de navegador como el que he descrito para ocultar las mejores prácticas de la barra de direcciones. La implementación que he explicado en este tutorial se ha probado en un Android Nexus S, iPhone 3GS y un iPhone 4, pero es muy posible que haya perdido un caso de ventaja en algún lugar. Tampoco estoy seguro de que la implementación mostrada continuará funcionando como está en el futuro, por lo que me sorprendió mucho encontrar tantos marcos web primarios (por ejemplo, iUI, jQuery Mobile, SenchaTouch) y prominentes sitios web (por ejemplo, Gmail, Yahoo, Apple) que dependen de alguna variación personalizada de este truco. Creo que la razón es simple: actualmente no existe una mejor solución que no sea javascript..

Envolver

Tenía tres intenciones principales al escribir un tutorial tan profundo sobre lo que puede parecer un tema trivial.

Primero, quería proporcionar un fragmento de código JavaScript puro para lograr este efecto que sea más sólido que la mayoría de los otros que he encontrado. Espero haberlo logrado adaptándome a los cambios de orientación, enlaces de anclaje y problemas de altura de contenido.

En segundo lugar, quería disipar parte de la magia detrás de cómo los marcos como SenchaTouch o iUI han hecho posible este efecto. Cuando inicialmente decidí usar SenchaTouch para un proyecto independiente hace algún tiempo, la "magia" del marco para hacer que las aplicaciones llenen la pantalla fue uno de los principales efectos de UX que me atrajeron. Es importante darse cuenta de que este mismo efecto se puede implementar fácilmente en JS puro independientemente de si elige utilizar un marco de JavaScript en su proyecto o no..

Finalmente, la razón principal por la que quería abordar este tema con tanto detalle es para crear conciencia sobre cuán inestable realmente es este enfoque. A pesar del hecho de que las variaciones de este truco se han adoptado ampliamente, creo que es, en el mejor de los casos, un poco poco elegante y, en el peor, un hack no confiable que depende del navegador y que puede continuar o no en el futuro. Me gustaría instar a aquellos en el negocio de los navegadores y la comunidad de desarrollo web / móvil en su conjunto a impulsar un enfoque independiente de JavaScript más basado en estándares para lidiar con esta consideración de UX. Creo que el método de metaetiqueta que Apple ha implementado es un gran paso en la dirección correcta, pero, como se mencionó anteriormente, no satisface suficientemente las necesidades de la comunidad de desarrollo..

La verdadera pregunta es: ¿qué te parece? Vamos a hablar de ello en la sección de comentarios a continuación..

Mejorar este código

No tengo dudas de que algunos de nuestros lectores pueden mejorar el código que proporcioné en este tutorial. Si ve algo en esta publicación que podría optimizarse o mejorarse, ¡deje sus comentarios a continuación! También puedes contactarme a través de Twitter (@markhammonds), aunque a veces me toma un tiempo responder a Tweets o DM. La mejor manera de contactarme es a través de los comentarios a continuación o con el formulario de contacto en Mobileuts +. Si acepto una de sus sugerencias de mejora, actualizaré esta publicación y citaré su nombre o dirección.!

Referencias

No quiero tomar mi palabra para ninguno de los anteriores?

Eche un vistazo a los siguientes recursos con los que me topé mientras investigaba esta publicación:

  • Configurando aplicaciones web, Safari Developer Library
  • "Mobifying" su sitio HTML5, Eric Bidelman
  • Ocultar la barra de direcciones dentro de las aplicaciones web móviles, David Walsh
  • Aplicaciones Web para iPhone 101: sacar a Safari del camino, Niels Leenheer