Construindo uma linha do tempo horizontal com CSS e JavaScript

Em um post anterior, mostrei como construir uma linha do tempo vertical responsiva do zero. Hoje, abordarei o processo de criação do associado horizontal Linha do tempo.

Como de costume, para ter uma ideia inicial do que vamos construir, dê uma olhada na demonstração relacionada do CodePen (confira a versão maior para uma melhor experiência):

Temos muito a cobrir, então vamos começar!

1. Marcação HTML

A marcação é idêntica à marcação que definimos para a linha do tempo vertical, exceto por três pequenas coisas:

  • Usamos uma lista ordenada em vez de uma lista não ordenada, pois isso é mais semanticamente correto.
  • Há um item de lista extra (o último) que está vazio. Em uma próxima seção, discutiremos o motivo.
  • Há um elemento extra (ou seja, .arrows) que é responsável pela navegação na linha do tempo.

Aqui está a marcação necessária:

O estado inicial da linha do tempo é assim:

2. Adicionando estilos CSS iniciais

Depois de alguns estilos básicos de fonte, estilos de cores, etc. que omiti aqui para simplificar, especificamos algumas regras estruturais de CSS:

Mais importante aqui, você notará duas coisas:

  • Atribuímos grandes preenchimentos superiores e inferiores à lista. Novamente, explicaremos por que isso acontece na próxima seção.
  • Como você notará na demonstração a seguir, neste momento não podemos ver todos os itens da lista porque a lista tem width: 100vw e seu pai tem overflow-x: hidden. Isso efetivamente “mascara” os itens da lista. Graças à navegação na linha do tempo, no entanto, poderemos navegar pelos itens mais tarde.

Com essas regras em vigor, aqui está o estado atual da linha do tempo (sem nenhum conteúdo real, para manter as coisas claras):

3. Estilos de elementos da linha do tempo

Neste ponto, vamos estilizar o div elementos (vamos chamá-los de “elementos da linha do tempo” de agora em diante) que fazem parte dos itens da lista, bem como seus ::before pseudo-elementos.

Além disso, usaremos o :nth-child(odd) e :nth-child(even) Pseudoclasses CSS para diferenciar os estilos das divs ímpares e pares.

Aqui estão os estilos comuns para os elementos da linha do tempo:

Então alguns estilos para os estranhos:

E por fim alguns estilos para os pares:

Aqui está o novo estado da linha do tempo, com conteúdo adicionado novamente:

Como você deve ter notado, os elementos da linha do tempo estão absolutamente posicionados. Isso significa que eles são removidos do fluxo normal de documentos. Com isso em mente, para garantir que toda a linha do tempo apareça, temos que definir grandes valores de preenchimento superior e inferior para a lista. Se não aplicarmos nenhum preenchimento, a linha do tempo será cortada:

Como é a linha do tempo sem preenchimentosComo é a linha do tempo sem preenchimentosComo é a linha do tempo sem preenchimentos

4. Estilos de navegação da linha do tempo

Agora é hora de estilizar os botões de navegação. Lembre-se que por padrão desabilitamos a seta anterior e damos a ela a classe de disabled.

Aqui estão os estilos CSS associados:

As regras acima nos dão esta linha do tempo:

5. Adicionando interatividade

A estrutura básica da linha do tempo está pronta. Vamos adicionar alguma interatividade a ele!

Variáveis

Primeiro de tudo, configuramos um monte de variáveis ​​que usaremos mais tarde.

Inicializando coisas

Quando todos os recursos da página estiverem prontos, o init função é chamada.

Esta função aciona quatro subfunções:

Como veremos em breve, cada uma dessas funções realiza uma determinada tarefa.

Elementos da linha do tempo de altura igual

Se você voltar para a última demonstração, notará que os elementos da linha do tempo não têm alturas iguais. Isso não afeta a funcionalidade principal de nossa linha do tempo, mas você pode preferir que todos os elementos tenham a mesma altura. Para conseguir isso, podemos dar a eles uma altura fixa via CSS (solução fácil) ou uma altura dinâmica que corresponde à altura do elemento mais alto via JavaScript.

A segunda opção é mais flexível e estável, então aqui está uma função que implementa esse comportamento:

Essa função recupera a altura do elemento da linha de tempo mais alto e a define como a altura padrão para todos os elementos.

Veja como está a demo:

6. Animando a linha do tempo

Agora vamos nos concentrar na animação da linha do tempo. Construiremos a função que implementa esse comportamento passo a passo.

Primeiro, registramos um ouvinte de evento de clique para os botões da linha do tempo:

Cada vez que um botão é clicado, verificamos o estado desabilitado dos botões da linha do tempo e, se não estiverem desabilitados, nós os desabilitamos. Isso garante que ambos os botões sejam clicados apenas uma vez até que a animação termine.

Portanto, em termos de código, o manipulador de cliques contém inicialmente estas linhas:

Os próximos passos são os seguintes:

  • Verificamos se é a primeira vez que clicamos em um botão. Novamente, lembre-se de que o anterior botão está desabilitado por padrão, então o único botão que pode ser clicado inicialmente é o próximo 1.
  • Se de fato é a primeira vez, usamos o transform propriedade para mover a linha do tempo 280px para a direita. O valor do xScrolling variável determina a quantidade de movimento.
  • Pelo contrário, se já clicamos em um botão, recuperamos o atual transform valor da linha do tempo e adicionar ou remover a esse valor, a quantidade de movimento desejada (ou seja, 280px). Assim, desde que cliquemos no anterior botão, o valor do transform propriedade diminui e a linha do tempo é movida da esquerda para a direita. No entanto, quando o próximo botão é clicado, o valor do transform propriedade aumenta e a linha do tempo é movida da direita para a esquerda.

O código que implementa esta funcionalidade é o seguinte:

Bom trabalho! Acabamos de definir uma forma de animar a linha do tempo. O próximo desafio é descobrir quando essa animação deve parar. Aqui está nossa abordagem:

  • Quando o primeiro elemento da linha do tempo fica totalmente visível, significa que já chegamos ao início da linha do tempo e, portanto, desabilitamos o anterior botão. Asseguramos também que o próximo botão está habilitado.
  • Quando o último elemento fica totalmente visível, significa que já chegamos ao final da linha do tempo e, portanto, desabilitamos o próximo botão. Garantimos também, por isso, que a anterior botão está habilitado.

Lembre-se que o último elemento é um vazio com largura igual à largura dos elementos da linha de tempo (ou seja, 280px). Damos esse valor (ou um valor maior) porque queremos ter certeza de que o último elemento da linha do tempo estará visível antes de desabilitar o próximo botão.

Para detectar se os elementos de destino estão totalmente visíveis na janela de visualização atual ou não, aproveitaremos o mesmo código que usamos para a linha do tempo vertical. O código necessário que vem deste thread do Stack Overflow é o seguinte:

Além da função acima, definimos outro auxiliar:

Esta função adiciona ou remove o disabled classe de um elemento com base no valor da flag parâmetro. Além disso, pode alterar o estado desabilitado desse elemento.

Dado o que descrevemos acima, aqui está o código que definimos para verificar se a animação deve parar ou não:

Observe que há um atraso de 1,1 segundo antes de executar esse código. Por que isso acontece?

Se voltarmos ao nosso CSS, veremos esta regra:

Portanto, a animação da linha do tempo precisa de 1 segundo para ser concluída. Enquanto estiver concluído, esperamos 100 milissegundos e, em seguida, realizamos nossas verificações.

Aqui está a linha do tempo com animações:

7. Adicionando suporte para furto

Até agora, a linha do tempo não responde a eventos de toque. Seria bom se pudéssemos adicionar essa funcionalidade. Para isso, podemos escrever nossa própria implementação JavaScript ou usar uma das bibliotecas relacionadas (por exemplo, Hammer.js, TouchSwipe.js) que existem por aí.

Para nossa demonstração, manteremos isso simples e usaremos Hammer.js, então primeiro incluímos esta biblioteca em nossa caneta:

Como incluir Hammerjs em nossa canetaComo incluir Hammerjs em nossa canetaComo incluir Hammerjs em nossa caneta

Em seguida, declaramos a função associada:

Dentro da função acima, fazemos o seguinte:

  • Crie uma instância de Hammer.
  • Manipuladores de registro para o swipeleft e swiperight eventos.
  • Quando deslizamos sobre a linha do tempo na direção esquerda, acionamos um clique para o próximo botão e, assim, a linha do tempo é animada da direita para a esquerda.
  • Quando deslizamos sobre a linha do tempo na direção certa, acionamos um clique no botão anterior e, assim, a linha do tempo é animada da esquerda para a direita.

A linha do tempo com suporte para furto:

Adicionando navegação do teclado

Vamos aprimorar ainda mais a experiência do usuário fornecendo suporte para navegação pelo teclado. Nossos objetivos:

  • Quando o deixei ou tecla de seta para a direita for pressionado, o documento deve ser rolado para a posição superior da linha do tempo (se outra seção da página estiver visível no momento). Isso garante que toda a linha do tempo seja visível.
  • Especificamente, quando o tecla de seta para a esquerda for pressionado, a linha do tempo deve ser animada da esquerda para a direita.
  • Da mesma forma, quando o tecla de seta para a direita for pressionado, a linha do tempo deve ser animada da direita para a esquerda.

A função associada é a seguinte:

A linha do tempo com suporte para teclado:

8. Tornando-se responsivo

Estamos quase terminando! Por último, mas não menos importante, vamos tornar a linha do tempo responsiva. Quando a viewport for menor que 600px, ela deverá ter o seguinte layout empilhado:

Como estamos usando uma abordagem de desktop, aqui estão as regras de CSS que precisamos substituir:

Observação: Para duas das regras acima, tivemos que usar o !important regra para substituir os estilos inline relacionados aplicados por meio de JavaScript.

O estado final da nossa linha do tempo:

Suporte ao navegador

A demonstração funciona bem em todos os navegadores e dispositivos recentes. Além disso, como você deve ter notado, usamos Babel para compilar nosso código ES6 para ES5.

O único pequeno problema que encontrei durante o teste é a alteração de renderização de texto que acontece quando a linha do tempo está sendo animada. Embora eu tenha tentado várias abordagens propostas em diferentes threads do Stack Overflow, não encontrei uma solução direta para todos os sistemas operacionais e navegadores. Portanto, lembre-se de que você pode ver pequenos problemas de renderização de fonte enquanto a linha do tempo está sendo animada.

Conclusão

Neste tutorial bastante substancial, começamos com uma lista ordenada simples e criamos uma linha do tempo horizontal responsiva. Sem dúvida, cobrimos muitas coisas interessantes, mas espero que você tenha gostado de trabalhar para o resultado final e que tenha ajudado a adquirir novos conhecimentos.

Se você tiver alguma dúvida ou se houver algo que não tenha entendido, deixe-me saber nos comentários abaixo!

Próximos passos

Se você quiser melhorar ainda mais ou estender esse cronograma, aqui estão algumas coisas que você pode fazer:

  • Adicione suporte para arrastar. Em vez de clicar nos botões da linha do tempo para navegar, poderíamos simplesmente arrastar a área da linha do tempo. Para esse comportamento, você pode usar a API nativa de arrastar e soltar (que infelizmente não suporta dispositivos móveis no momento da escrita) ou uma biblioteca externa como Draggable.js.
  • Melhore o comportamento da linha do tempo à medida que redimensionamos a janela do navegador. Por exemplo, à medida que redimensionamos a janela, os botões devem ser habilitados e desabilitados de acordo.
  • Organize o código de uma maneira mais gerenciável. Talvez, use um padrão de design JavaScript comum.

Deixe um comentário

O seu endereço de e-mail não será publicado.