Создаем горизонтальный таймлайн с помощью CSS и JavaScript

Создаем горизонтальный таймлайн с помощью CSS и JavaScript

От автора: в предыдущем посте я рассказал вам, как создать адаптивный вертикальный таймлайн с нуля. Сегодня я покажу вам процесс создания горизонтального таймлайна. Как обычно, чтобы понять, что мы будем создавать, взгляните на демо ниже (см. большую версию).

У нас много работы, так начнем же! Разметка идентична разметке из вертикального таймлайна, только есть три отличия:

вместо ненумерованного списка мы используем нумерованный, так как это семантически правильнее;

есть дополнительный пустой элемент списка (последний), о котором мы поговорим ниже;

есть дополнительный элемент (.arrows), отвечающий за навигацию по таймлайну.

Изначально таймлайн выглядит следующим образом:

Добавляем первичные стили

Для упрощения я пропущу стили для шрифтов, цвета и т.д. и перейду к структурным CSS-правилам:

Вы заметите две самые важные вещи:

У списка заданы большие верхний и нижний padding’и. Зачем это нужно, мы объясним в следующей секции.

В демо ниже вы заметите, что пока что нам не видны все элементы списка, так как у списка есть свойство width: 100vw, а у его родителя overflow-x: hidden. Последнее свойство «маскирует» элементы списка. Чуть позже мы сможем перемещаться по элементам списка с помощью навигации.

На данный момент таймлайн выглядит следующим образом (без контента):

Стили элементов таймлайна

Теперь необходимо стилизовать теги div (мы будем называть их элементы таймлайна), которые входят в элементы списка вместе с псевдоэлементами ::before.

Чтобы различать стили для четных и нечетных элементов таймлайна, мы будем использовать псевдоклассы :nth-child(odd) и :nth-child(even).

Общие стили элементов таймлайна:

Стили для нечетных элементов:

И для четных элементов:

Теперь таймлайн с контентом выглядит так:

Возможно, вы заметили, что элементы таймлайна абсолютно позиционированы. Это значит, что они удалены из нормального потока в документе. Нам понадобилось задать большие значения верхнего и нижнего padding’а для списка, чтобы быть уверенными, что виден весь таймлайн. Если убрать padding, таймлайн будет обрезаться:

Создаем горизонтальный таймлайн с помощью CSS и JavaScript

Стили навигации таймлайна

Теперь нужно стилизовать кнопки навигации. Не забывайте, что по умолчанию мы отключаем кнопку назад и присваиваем ей класс disabled.

И наш таймлайн стал:

Добавляем интерактивность

Базовая структура таймлайна готова. Давайте сделаем ее интерактивной!

Переменные

Сперва мы зададим ряд переменных, которые нам потом пригодятся.

Инициализация объектов

Когда все элементы на странице готовы, вызывается функция init.

Эта функция вызывает 4 другие функции:

Чуть позже мы увидим, что каждая функция выполняет определенную задачу.

Элементы таймлайна с одинаковой высотой

Если вернуться к предыдущему демо, то можно заметить, что у элементов таймлайна разная высота. Это никак не влияет не главный функционал таймлайна, но, возможно, вы захотите, чтобы все элементы имели одинаковую высоту. Фиксированную высоту можно задать через CSS (простой способ), или же можно устанавливать динамическую высоту, равную высоте самого высокого элемента через JS.

Второй вариант более гибкий и стабильный. Функция, выполняющая описанные выше действия:

Функция вытягивает высоту самого высокого элемента в таймлайне и задает ее по умолчанию для всех элементов.

Анимируем таймлайн

Переходим к анимации таймлайна. Мы создали функцию, которая будет пошагово анимировать таймлайн.

Первым делом регистрируется обработчик события клика по кнопкам:

Каждый раз при клике мы проверяем состояние кнопок навигации на disabled, и если они активны, мы отключаем их. Так мы точно будем знать, что до конца анимации кнопки больше не будут нажиматься.

Обработчик клика состоит из этих строк:

Далее мы выполняем следующие шаги:

Мы проверяем, был ли это первый клик по кнопке. Не забывайте, что кнопка назад по умолчанию отключена, т.е. изначально можно кликнуть только по кнопке вперед.

Если кнопка нажата первый раз, мы двигаем таймлайн на 280px вправо с помощью свойства transform. Сдвиг задается в переменной xScrolling.

Если же на кнопку уже нажимали, мы получаем текущее значение transform и добавляем к нему или удаляем из него сдвиг (280px). То есть если кликнуть на кнопку назад, значение transform уменьшится, и таймлайн сдвинется слева направо. Если кликнуть на кнопку вперед, значение transform увеличится, и таймлайн сдвинется справа налево.

Код для этих шагов:

Замечательно! Мы определили анимацию таймлайна. Теперь необходимо понять, когда анимация должна останавливаться. Наш подход:

Когда первый элемент таймлайна полностью становится видимым, это значит, что мы достигли начала таймлайна, поэтому мы отключаем кнопку назад. Также проверяем, чтобы кнопка вперед была активной.

Когда последний элемент таймлайна полностью становится видимым, это значит, что мы достигли конца таймлайна, поэтому мы отключаем кнопку вперед. Также проверяем, чтобы кнопка назад была активной.

Не забывайте, что последний элемент пустой, и его ширина равна ширине элементов таймлайна (т.е. 280px). Мы задали это значение (или больше), чтобы убедиться, что последний элемент попал в поле зрения перед отключением кнопки вперед.

Чтобы определить, попал ли целевой элемент полностью во вьюпорт или нет, мы возьмем код для вертикального таймлайна. Код взят из ветки Stack Overflow:

Вне функции сверху мы задаем еще один хелпер:

Эта функция добавляет и удаляет класс disabled на элемент на основе значения параметра flag. Также функция умеет менять состояние disabled для этого элемента.

Учитывая все вышесказанное, ниже представлен код проверки для остановки анимации:

Заметили, что перед выполнением этого кода стоит задержка в 1.1 секунды? Зачем так делать? Если вернуться в CSS, там есть это правило:

Анимация таймлайна выполняется за 1 секунду. Далее мы ждем 100 миллисекунд и выполняем проверки. Таймлайн с анимацией:

Добавляем поддержку свайпов

Пока что таймлайн никак не реагирует на события касаний. Хорошо бы добавить этот функционал. Можно написать свой JS-способ, а можно взять готовую библиотеку (Hammer.js или TouchSwipe.js).

Не будем усложнять и для простоты возьмем Hammer.js. Первым делом добавляем библиотеку в Pen:

Создаем горизонтальный таймлайн с помощью CSS и JavaScript

Затем объявляем функцию:

В функции сверху мы:

создаем объект Hammer;

регистрируем обработчики для событий swipeleft и swiperight;

когда мы делаем свайп влево, мы вызываем клик по кнопке вперед, и таймлайн сдвигается справа налево;

когда мы делаем свайп вправо, мы вызываем клик по кнопке назад, и таймлайн сдвигается слева направо.

Таймлайн с поддержкой свайпов:

Добавляем навигацию по клавиатуре

Давайте улучшим UX и добавим поддержку навигации по клавиатуре. Наши цели:

При нажатии кнопок влево и вправо документ должен скролиться к верхней позиции таймлайна (если другая секция страницы сейчас видима). Так весь таймлайн будет виден.

При нажатии стрелки влево таймлайн должен анимироваться слева направо.

При нажатии стрелки вправо таймлайн должен анимироваться справа налево.

Соответствующая функция:

Таймлайн с поддержкой клавиатуры:

Добавляем адаптивность

Почти закончили! Последний, но не менее важный этап – давайте сделаем таймлайн адаптивным. Когда вьюпорт меньше 600px, макет должен переключаться на такой стек:

Создаем горизонтальный таймлайн с помощью CSS и JavaScript

Так как мы используем подход desktop-first, ниже представлены CSS-правила, которые необходимо переписать:

Заметка: в двух правилах в коде сверху нам пришлось использовать !important, чтобы переписать инлайновые стили, примененные через JS.

Финальный таймлайн:

Поддержка в браузерах

Демо хорошо работает во всех последних версиях браузеров и устройств. Также вы могли заметить, что мы компилировали наш ES6-код в ES5 с помощью Babel.

Единственная маленькая проблема, с которой я столкнулся при тестировании, заключалась в изменении текста при анимировании. Я испробовал разные подходы со Stack Overflow, но не смог найти простого решения для всех операционных систем и браузеров. Так что знайте, что во время анимации могут возникать небольшие проблемы с рендерингом текста.

Заключение

В этом довольно объемном уроке мы начали с простого нумерованного списка и закончили адаптивным горизонтальным таймлайном. Могу с уверенностью сказать, что мы изучили много чего интересного. Надеюсь, вам понравилась наша работа, и вы почерпнули из нее что-то новое.

Автор: George Martsoukos

Источник: //webdesign.tutsplus.com/

Редакция: Команда webformyself.

Метки:

Похожие статьи:

Комментарии Вконтакте: