Advertisement
  1. Code
  2. Mobile Web Apps

Aplicaciones web de pantalla completa

by
Read Time:15 minsLanguages:

Spanish (Español) translation by Luis Chiabrera (you can also view the original English article)

Uno de los primeros problemas que se encuentran 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 demostrará cómo recuperar el espacio de la pantalla que, de otro modo, se perdería en la barra de direcciones mientras se tienen en cuenta los cambios de orientación, los problemas de altura del contenido y los enlaces de documentos internos.

Cambios posteriores en las técnicas y el software

Ciertos aspectos de las aplicaciones o técnicas utilizadas en este tutorial han cambiado desde que se publicó originalmente. Esto puede dificultar un poco el seguimiento. Recomendamos mirar estos tutoriales más recientes sobre el mismo tema:

Definiendo el problema

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

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

Web site with browser chromeWeb site with browser chromeWeb site with browser chrome

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

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

Web site without browser chromeWeb site without browser chromeWeb site without browser chrome

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 una ganancia total de 104 píxeles lógicos de espacio de pantalla vertical (la cantidad de espacio ganado en los dispositivos Android varía , pero el resultado es similar). Al intentar crear una experiencia inmersiva, es fácil ver en las capturas de pantalla anteriores qué gran diferencia puede hacer un cambio tan pequeño.

Desafortunadamente, los principales navegadores web móviles aún 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, existen dos enfoques comunes para realizar el trabajo, y ambos se abordarán en este tutorial.

El enfoque de las meta etiquetas

Si tu aplicación web solo está orientada a iOS, la solución ideal es establecer la siguiente meta etiqueta en la parte <head> de tu documento HTML:

Al hacerlo, se eliminarán por completo 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 funcionará de manera confiable en dispositivos iOS, existe 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 Safari móvil.

Adding web app to home screenAdding web app to home screenAdding web app to home screen

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

Obviamente, esto 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 usen mientras navegan por la web de manera casual.

Quizás algún día los proveedores de navegadores se unirán y proporcionarán una única meta etiqueta multiplataforma para un control detallado de la interfaz de usuario del navegador sin obstruir el flujo normal de aplicaciones del navegador web (cómo sería la vida si esto realmente ocurriera). Hasta entonces, tendremos que tomar las cosas en nuestras manos a la antigua usanza: 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 en 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, serán incapaces de abandonar el sitio sin reiniciar completamente el navegador.

Contra-contrapunto: Creación de 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 mediante una combinación de un efecto de desvanecimiento de entrada y salida y el 'doble toque' gestos o tal vez forzando el lanzamiento de aplicaciones de pantalla completa en una nueva ventana) podría lograr un equilibrio entre ambos intereses.

El enfoque JavaScript

Muchos de los marcos de aplicaciones web multiplataforma ahora disponibles han llegado a depender de lo que es esencialmente un truco de JavaScript para acercarse lo más posible a brindar una experiencia de pantalla completa. Todos los siguientes marcos incluyen alguna variación de la solución de JavaScript que demostraré en este tutorial:

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éntete libre de bifurcar, modificar o sugerir cambios. Solo ten en cuenta que, en el mejor de los casos, se trata de un truco dependiente del navegador. Puede cambiar en el futuro. Puede que no cubra todos los casos extremos. No está probado en Blackberry y Windows Phone 7.

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

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

Adentrándose en el agujero del conejo 

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

La llamada scrollTo es un método del objeto window del navegador con la siguiente firma:

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 eje Y 1 píxel? ¿No deberían ser 60 píxeles para el iPhone? Ese fue también mi pensamiento inicial. Sin embargo, la barra de direcciones no es técnicamente parte de la ventana gráfica del documento. En lugar de desplazar el contenido 60 píxeles hacia abajo, en realidad estamos aprovechando una peculiaridad de WebKit (¿error?) Que eliminará automáticamente la barra de direcciones cuando se llame al método scrollTo. En mis pruebas, pude lograr el efecto deseado en iOS estableciendo el valor Y en cualquier número entero, incluidos -10, 0, 1 o 60. Sin embargo, en Android, solo los números enteros positivos lograron el efecto deseado, por lo que "1" es el mejor desplazamiento Y para usar en el hack del navegador.

El siguiente paso es determinar cuándo llamar al método scrollTo. 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:

Agregando un detector de eventos:

Agregando un detector de eventos en línea:

Dentro de una etiqueta de script incrustada (para aquellos que se sienten rebeldes):

Si pruebas estos tres ejemplos 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 sucederá nada.

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

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

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

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

Entonces, en mi ejemplo, proporcioné una función anónima que contiene la llamada scrollTo para que se ejecute después de un retraso de 100 milisegundos. Por extraño que parezca, lo anterior todavía me funcionó independientemente del número entero proporcionado para el retraso de milisegundos. Funcionó con -100, 0 y 1 tan bien como con 100. En consecuencia, mi recomendación es usar 0 para el argumento de milisegundos.

Hasta este punto, nuestra barra de direcciones que oculta un fragmento de JavaScript debería parecerse a uno de los siguientes ejemplos:

Detector de eventos:

Detector de eventos en línea:

¡Excelente! Entonces, ahora podemos pasar a construir algo realmente útil, ¿verdad? Lamentablemente no. Todavía hay varios problemas específicos del navegador que pueden estropear este truco.

Altura de contenido insuficiente

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

Opción 1: establecer Initial-Scale

El primer enfoque es modificar el initial-scale de tu página web hasta que tu contenido ocupe toda la ventana gráfica. Puedes hacer esto con la siguiente meta etiqueta:

Tendrás que jugar con el valor de initial-scale hasta que encuentres la cantidad de escala/zoom que coincida con tus necesidades específicas.

Opción 2: establece una altura mínima

El segundo enfoque es utilizar un atributo CSS simple. Puedes aplicar un valor de min-height suficientemente grande a la etiqueta body o cualquier otro elemento de nivel de bloque en tu página para tener en cuenta el espacio en blanco vacío. Sin embargo, debes tener cuidado aquí por dos razones: el valor de píxel exacto que necesita el atributo de min-height variará según el initial-scale (es decir, el zoom) de la página y el valor cambiará si el usuario gira de retrato a modo paisaje o viceversa. La sintaxis básica para establecer el atributo min-height en la etiqueta del cuerpo se muestra a continuación:

Nuevamente: el valor de píxel real utilizado depende del initial-scale/zoom de tu 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 comparar dinámicamente la propiedad document.height con la propiedad window.outerHeight y luego aumentar dinámicamente el tamaño de document.height cuando sea necesario.

El siguiente fragmento de código JavaScript es una solución que sin marco para este problema:

En las líneas 5 y anteriores, agregué una cantidad aparentemente arbitraria de relleno (+50). Esto era necesario para que el efecto funcionara tanto en iOS como en Android. También tuve que reposicionar la llamada a setTimeout ya que 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 necesitaba reposicionar la llamada setTimeout, sino que para iOS también tuve que agregar un retraso aparentemente arbitrario de +50 si acababa de cambiar la altura del documento. Este no era el caso inicialmente (cuando se usa el detector load sin establecer un nuevo valor para la altura del documento).

Enlaces Internal/Anchor

Las variaciones del hack del navegador anterior ya están ampliamente implementadas en la web. Sin embargo, hay al menos un caso de uso en el que forzar al navegador a desplazarse a 0,1 es exactamente el enfoque incorrecto: los visitantes que llegan a tu sitio a través de un enlace anchor(también conocido como internal). Para adaptarse a este caso extremo, solo necesitas llamar a 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 detector de eventos de load dentro de ese condicional. Hacerlo nos deja con algo como lo siguiente:

Cambios en la orientación del dispositivo

Otro problema que puedes 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, la compensación desplazamiento no se cambiará automáticamente (Android no parece sufrir este problema). Esto significa que tu usuario se quedará en algún lugar de la página más abajo de lo previsto.

La solución para esto es configurar un detector de eventos en window.onorientationchange para que se le notifique cuando cambie la orientación, y luego ejecutar la llamada window.scrollTo(0, 1) nuevamente después de que ocurra el cambio.

Este parece 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 queda lo siguiente:

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 tu proyecto: ¿qué pasa si el usuario se ha desplazado significativamente hacia abajo en la página antes de cambiar la orientación del dispositivo? En ese caso, restablecer la pantalla a 0, 1 haría que el usuario perdiera su lugar en el documento. Tener en cuenta esto es muy específico de la implementación, pero la esencia es simplemente establecer un umbral del eje 'y' y luego solo restablecer el desplazamiento de desplazamiento a 0, 1 si el usuario aún no se ha desplazado más allá de ese umbral.

Bloqueando la barra de direcciones fuera de la pantalla

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

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

Que yo sepa, actualmente no existe una solución para eliminar la barra de herramientas / barra de botones en iOS desde la parte inferior de Mobile Safari solo con JavaScript. La única forma que conozco de lograr este efecto es el enfoque de meta etiqueta explicado al comienzo de este tutorial. ¡Corrígeme si estoy equivocado!

Haciéndolo condicional

Una consideración con el enfoque anterior que aún no se ha discutido es cómo manejar a los usuarios que visitan desde un navegador web no móvil o no compatible. Hay varios métodos diferentes para determinar qué navegador está accediendo actualmente a tu sitio. Si estás trabajando con un lenguaje de secuencias de comandos del lado del servidor, es posible que desees determinar si el usuario está en un dispositivo móvil en el momento en que se genera la página y solo proporcione este truco cuando sea necesario. Quizás un enfoque más sólido sería realizar las pruebas de forma dinámica con JavaScript. Aplicar esta consideración está más allá del alcance de este tutorial, pero deja tus sugerencias en los comentarios.

Caveat Emptor!

Los hacks del navegador como el que he descrito para ocultar la barra de direcciones desafían las mejores prácticas. La implementación que he explicado en este tutorial ha sido probada en un Android Nexus S, iPhone 3GS y un iPhone 4, pero es muy posible que me haya perdido un caso extremo en alguna parte. Tampoco estoy del todo seguro de que la implementación mostrada continuará funcionando como está en el futuro, por lo que me sorprendió bastante encontrar tantos de los marcos web principales (por ejemplo, iUI, jQuery Mobile, SenchaTouch) y destacados sitios web (por ejemplo, Gmail, Yahoo, Apple) que se basan en alguna variación personalizada de este truco. La razón, creo, es simple: actualmente no existe una solución mejor que no sea JavaScript.

Finalizando

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 JavaScript puro para lograr este efecto que es más sólido que la mayoría de los otros que he encontrado. Espero haberlo logrado al adaptarme a los cambios de orientación, los enlaces de anclaje y los problemas de altura del 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 eliges o no utilizar un marco de JavaScript en tu proyecto.

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

La verdadera pregunta es: ¿qué opinas? Hablemos de ello en la sección de comentarios a continuación.

Mejora este código

No tengo ninguna duda de que algunos de nuestros lectores pueden mejorar el código que he proporcionado en este tutorial. Si ves algo en esta publicación que podría optimizarse o mejorarse, ¡deja tus comentarios a continuación! También puedes comunicarte conmigo a través de Twitter (@markhammonds), aunque a veces me toma un tiempo responder a los tweets o mensajes directos. La mejor manera de comunicarse conmigo es en los comentarios a continuación o con el formulario de contacto en Mobileuts+. Si acepto una de tus sugerencias de mejora, actualizaré esta publicación y citaré tu nombre o identificador.

Referencias

¿No quieres tomar mi palabra por nada de lo anterior?

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

Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.