Advertisement
  1. Web Design
  2. UI Design

Elaborando una Línea de Tiempo Horizontal Con  CSS y JavaScript

by
Difficulty:IntermediateLength:LongLanguages:

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

En un post previo, te mostré cómo crear una línea de tiempo vertical responsiva desde cero. Hoy, cubriré el proceso de crear la línea de tiempo horizontal asociada.

Como es habitual, para obtener una idea inicial de lo que estaremos creando, ve el demo relacionado en CodePen (consulta la versión más grande para una mejor experiencia):

Tenemos mucho que cubrir, así que ¡comencemos!

1. Marcado HTML

El marcado es idéntico al marcado que definimos para la línea de tiempo vertical, aparte de tres pequeñas cosas:

  • Usamos una lista ordenada en lugar de una lista desordenada pues es más semánticamente correcto.
  • Hay un elemento extra en la lista (el último) que está vacío. En una próxima sección, discutiremos la razón.
  • Hay un elemento extra (es decir .arrows) que es responsable de la navegación de la línea de tiempo.

Aquí está el marcado requerido:

El estado inicial de la línea de tiempo se ve así:

2. Añadiendo Estilos CSS Iniciales

Después de algunos estilos de fuente básicos, estilos de color, etc. que he omitido aquí por simpleza, especificamos algunas reglas CSS estructurales:

Lo más importante aquí, notarás dos cosas:

  • Asignamos padding grande inferior y superior a la lista. De nuevo, explicaremos por qué ello ocurre en la próxima sección.
  • Como notarás en el siguiente demo, en éste punto no podemos ver todos los elementos de la lista porque la lista tiene width:100vw y su padre tiene overlfox-x:hidden. Ésto efectivamente "enmascara" los elementos de la lista. Sin embargo, gracias a la navegación de la línea de tiempo, podremos navegar a través de los elementos más adelante.

Con éstas reglas en su lugar, aquí está el estado actual de la línea de tiempo (sin ningún contenido real, para mantener las cosas claras):

3. Estilos de Elementos de la Línea de Tiempo

En éste punto aplicaremos estilo a los elementos div (los llamaremos "elementos de línea de tiempo" de aquí en adelante) que son parte de los elementos de la lista así como sus pseudo-elementos ::before.

Adicionalmente, usaremos las pseudo-clases CSS :nth-child(odd) y :nth-child(even) para diferenciar los estilos para los divs pares e impares.

Aquí están los estilos comunes para los elementos de la línea de tiempo:

Luego algunos estilos para los impares:

Y finalmente algunos estilos para los pares:

Aquí está el nuevo estado de la línea de tiempo, de nuevo con contenido añadido:

Como probablemente lo has notado, los elementos de la línea de tiempo estás posicionados absolutamente. Ello significa que son removidos del flujo normal del documento. Con ello en mente, para asegurar que toda la línea de tiempo aparezca, tenemos que establecer los valores grandes de padding superior e inferior para la lista. Si no aplicamos ningún padding, la línea de tiempo será recortada:

How the timeline looks like without paddings

4. Estilos de Navegación de la Línea de Tiempo

Ahora es momento de aplicar estilo a los botones de navegación. Recuerda que por defecto deshabilitamos la flecha previa y le damos la clase de disabled.

Aquí están los estilos CSS asociados:

Las reglas de arriba nos dan ésta línea de tiempo:

5. Agregando Interactividad

La estructura básica de la línea de tiempo está lista. ¡Agreguemos algo de interactividad a ella!

Variables

Primero lo primero, definimos un conjunto de variables que utilizaremos más adelante.

Inicializando las Cosas

Cuando todos los recursos de la página están listos, la función init es llamada.

Ésta función desencadena cuatro sub-funciones:

Como veremos en un momento, cada una de éstas funciones realiza una cierta tarea.

Elementos de la Línea de Tiempo de Igual Altura

Si regresas al último demo, notarás que los elementos de la línea de tiempo no tienen alturas iguales. Ésto no afecta la funcionalidad principal de nuestra línea de tiempo, pero podrías preferirlo si todos los elementos tuvieran la misma altura. Para lograr ésto, podemos darles una altura fija vía CSS (solución fácil) o una altura dinámica que corresponde a la altura del elemento más alto vía JavaScript.

La segunda opción es más flexible y estable, así que aquí está una función que implementa éste comportamiento:

Ésta función toma la altura del elemento más alto de la línea de tiempo y la establece como la altura predeterminada para todos los elementos.

Aquí está cómo se ve el demo:

6. Animando la Línea de Tiempo

Ahora vamos a enfocarnos en la animación de la línea de tiempo. Crearemos la función que implementa éste comportamiento paso-a-paso.

Primero, registramos un click event listener para los botones de la línea de tiempo:

Cada vez que se hace click en un botón, verificamos el estado deshabilitado de los botones de la línea de tiempo y si no están deshabilitados, los deshabilitamos. Ésto asegura que en ambos botones se hará click una vez hasta que finalice la animación.

Así que, en términos de código, el click handler inicialmente contiene éstas líneas:

Los próximos pasos son como sigue:

  • Verificamos si es la primera vez que hemos hecho click en un botón. De nuevo, ten en mente que el botón previo es deshabilitado por defecto, así que el único botón que puede aplicarse un click inicialmente es el siguiente.
  • Si en efecto es la primera vez, usamos la propiedad transform para mover la línea de tiempo 280px a la derecha. El valor de la variable xScrolling determina la cantidad de movimiento.
  • En caso contrario, si ya hemos hecho click en un botón, tomamos el valor actual de transform de la línea de tiempo y agregamos o removemos ese valor, la cantidad deseada de movimiento (es decir 280px). Así que, mientras hacemos click en el botón previo, el valor de la propiedad transform decrece y la línea de tiempo es movida de izquierda a derecha. Sin embargo, cuando el botón siguiente recibe un click, el valor de la propiedad transform se incrementa y la línea de tiempo es movida de derecha a izquierda.

El código que implementa ésta funcionalidad es como sigue:

¡Magnífico trabajo! Acabamos de definir una manera de animar la línea de tiempo. El próximo desafío es averiguar cuando ésta animación debería parar. Aquí está nuestro planteamiento:

  • Cuando el primer elemento de la línea de tiempo llega a ser completamente visible, significa que ya hemos alcanzado el inicio de la línea de tiempo, y así deshabilitamos el botón previo. También aseguramos que el botón siguiente esté habilitado.
  • Cuando el último elemento llega a ser completamente visible, significa que ya hemos llegado al final de la línea de tiempo, y así deshabilitamos el botón siguiente. También, por lo tanto, aseguramos que el botón previo está habilitado.

Recuerda que el último elemento es uno vacío con anchura igual a la anchura de los elementos de la línea de tiempo (es decir 280px). Le damos éste valor (o uno más alto) porque queremos asegurar que el último elemento de la línea de tiempo será visible antes de deshabilitar el botón siguiente.

Para detectar si los elementos objetivo están o no totalmente visibles en la ventana gráfica actual, aprovecharemos el mismo código usado pra la línea de tiempo vertical. El código requerido que viene de ésta  consulta de Stack Overflow  es como sigue:

Más allá de la función de arriba, definimos otro helper:

Ésta función añade o remueve la clase disabled de un elemento basado en el valor del parámetro flag. Además, puede cambiar el estado deshabilitado para éste elemento.

Dado lo que hemos descrito arriba, aquí está el código que definios para verificar si la animación debería o no parar:

Nota que hay un 1.1 segundo de retraso antes de ejecutar éste código. ¿Por qué ocurre ésto?

Si regresamos a nuestro CSS, veremos ésta regla:

Así que, la animación de la línea de tiempo necesita 1 segundo para completarse. Mientras se completa, esperamos 100 milisegundos y luego, ejecutamos nuestras verificaciones.

Aquí está la línea de tiempo con animaciones:

7. Agregando Soporte de Deslizamiento

Hasta ahora, la línea de tiempo no responde a eventos touch. Aunque sería agradable si pudiéramos agregar ésta funcionalidad. Para lograrlo, podemos escribir nuestra implementación JavaScript o usar uno de las librerías relacionadas (por ejemplo Hammer.js, TouchSwipe.js) que existen.

Para nuestro demo, mantendremos ésto sencilo y usemos Hammer.js, así que primero, incluímos ésta librería en nuestro pen:

How to include Hammerjs in our pen

Luego declaramos la función asociada:

Dentro de la función de arriba, hacemos lo siguiente:

  • Crea una instancia de Hammer.
  • Registra handlers para los eventos swipeleft y swiperight.
  • Cuando nos deslizamos sobre la línea de tiempo en la dirección izquierda, desencadenamos un click en el botón siguiente, y así la línea de tiempo es animada de derecha a izquierda.
  • Cuando nos deslizamos por la línea de tiempo en la dirección derecha, desencadenamos un click en el botón previo, y así la línea de tiempo es animada de izquierda a derecha.

La línea de tiempo con soporte de deslizamiento:

Agregando Navegación de Teclado

Mejoremos más la experiencia de usuario al brindar soporte para navegación por teclado. Nuestras metas:

  • Cuando la tecla flecha izquierda o derecha es presionada, el documento debería ser desplazado a la posición superior de la línea de tiempo (si otra sección de página es actualmente visible). Ésto asegura que toda la línea de tiempo será visible.
  • Específicamente, cuando la tecla flecha izquierda es presionada, la línea de tiempo debería ser animada de izquierda a derecha.
  • De la misma manera, cuando la tecla flecha derecha es presionada, la línea de tiempo debería ser animada de derecha a izquierda.

La función asociada es la siguiente:

La línea de tiempo con soporte de teclado:

8. Convirtiéndose en Responsiva

¡Casi terminamos! Al último pero no menos importante, hagamos responsiva la línea de tiempo. Cuando la ventana gráfica es inferior a 600 px, debería tener el siguiente maquetado apilado:

Como estamos usando un planteamiento de primero-escritorio, aquí están las reglas CSS que tenemos que sobreescribir:

Nota: Para dos de las reglas de arriba, tuvimos que usar la regla !important para sobreescribir los estilos inline relacionados aplicados a través de JavaScript.

El estado final de nuestra línea de tiempo:

Soporte de Navegadores

El demo funcona bien en todos los navegadores modernos y dispositivos. También, como posiblemente lo has notado, usamos Babel para compilar nuestro código ES6 a ES5.

El único pequeño problema que encontré mientras lo probaba es el cambio de renderizado de texto que ocurre cuando la línea de tiempo está siendo animada. Aunque intenté varios planteamientos propuestos en diferentes consultas en Stack Overflow, no encontré una solución sencilla para todos los sistemas operativos y navegadores. Así que, ten en mente que podrías ver pequeños problemas de renderizado de fuente cuando la línea de tiempo está siendo animada.

Conclusión

En éste tutorial sustancioso, comenzamos con una simple lista ordenada y creamos una línea de tiempo horizontal responsiva. Sin duda, cubrimos muchas cosas interesantes, pero espero que hayas disfrutado trabajando para el resultado final y que te haya ayudado a adquirir algún nuevo conocimiento.

Si tienes alguna pregunta o si hay cualquier cosa que no entendiste, ¡házmelo saber en los comentarios abajo!

Próximos Pasos

Si quieres mejorar más o extender ésta línea de tiempo, aquí están unas cuantas cosas que puedes hacer:

  • Agregar soporte para arrastrar. En lugar de hacer click en los botones de la línea de tiempo para navegar, podríamos solo arrastrar el área de la línea de tiempo. Para éste comportamiento, podrías usar la nativa Api Drag and Drop (que desafortunadamente no soporta dispositivos móviles al momento de escribir éste artículo) o una librería externa como Draggable.js.
  • Mejora el comportamiento de la línea de tiempo mientras redimensionamos la ventana del navegador. Por ejemplo, cuando redimensionamos la ventana, los botones deberían estar habilitados o deshabilitados consecuentemente.
  • Organiza el código en una manera más manejable. Quizá, usar un común Patrón de Diseño de JavaScript.
Advertisement
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.