Адаптивная галерея изображений для сайта на JavaScript.

Содержание:

Вступление.

Галерея изображений становится неотъемлемой частью любого сайта и, тем более, продающего лендинга. В этой статье я расскажу вам, как создать адаптивную галерею начиная с HTML-вёрстки и заканчивая JavaScript, подключить к ней различные способы управления прокруткой, в том числе с использованием swipe.

Для начала составим техническое задание на создание адаптивной галереи изображений:

  1. Галерея должна быть адаптивной и должна корректно работать на любом устройстве с разрешением от 320px и выше.
  2. Для управления галерей изображений используем максимально возможные варианты:
    — кнопками навигации «prev» и «next»;
    — пагинация;
    — клавишами клавиатуры со стрелочками «вправо» и «влево»;
    — вращением колёсика мыши;
    — перетаскивание с помощью курсора мыши;
    — на мобильных устройствах пролистывание пальцем (swipe);
    — автоматическое прокручивание галереи.
  3. Перечисленные способы навигации можно комбинировать, подключать или отключать при необходимости.
  4. Переход к следующему изображению при перетаскивании осуществиться, если изображение было перемещено на расстояние не менее 50% от его ширины. В противном случае, слайдер плавно вернётся к текущему изображению.
  5. Возможно использование нескольких галерей на одной странице.

HTML-вёрстка адаптивной галереи изображений.

Сначала я вам представлю HTML-вёрстку галереи изображений, а потом её прокомментирую.

Вся галерея изображений размещена в родительском контейнере с id="gallery".
Контейнер <div class="slider"> определяет размер видимой части нашей адаптивной галереи. Количество одновременно показываемых изображений в данном контейнере определяется в настойках. Для того, чтобы остальные изображения были невидимы, к контейнеру применяется стиль visibility: hidden;.
Все элементы галереи изображений размещены в контейнере <div class="stage">. Изменяя его позиционирование относительно родительского элемента, мы получим прокрутку галереи.

В контейнере <div class="control"> расположено управление пошаговой и постраничной навигации:

  1. Элементы управления, расположенные в контейнере <div class="nav-ctrl">, отвечают за прокручивание галереи на один шаг (одно изображение). Можно из этих элементов убрать текст, разместить их справа и слева от галереи и отобразить в них стрелочки «вправо» и «влево», используя фоновые изображения. Никакое изменение вёрстки при этом не требуется, достаточно внести изменения в таблицу стилей.
  2. В немаркированном списке <ul class="dots-ctrl"></ul> будут располагаться элементы постраничной навигации. Они генерируются скриптом в зависимости от настроек галереи изображений.

В вёрстке допущены пару упрощений, которые не влияют на работоспособность галереи, но подробно останавливаться на них в рамках данной статьи нет смысла — это отдельная тема.

  1. При клике на изображение не будет открываться его полноразмерный вариант.
  2. В HTML-вёрстке сразу присутствует код элементов как пошаговой, так и постраничной навигации. Достаточно было бы вставить в вёрстку только их родительский элемент — <div class="control">, а саму навигацию создавать «на лету» с помощью JavaScript, в зависимости от настроек галереи изображений.

Таблица стилей для адаптивной галереи изображений.

Небольшая таблица стилей, которая определяет внешний вид галереи изображений и навигации.

Инициализация адаптивной галереи изображений.

Первое, что мы сделаем, это создадим анонимную самозапускающуюся функцию, внутри которой и будет расположен наш код.
Нужно взять за правило ограничивать область видимости скрипта, чтобы исключить конфликты с другими JS-скриптами подключенными к странице.

Конструктор для адаптивной галереи изображений.

Для реализации возможности размещения нескольких галерей на одной странице, используем прототипный стиль написания скрипта. Для этой цели необходимо создать конструктор, который будет вызываться при инициализации каждой галереи.
Конструктор представляет из себя функциональное выражение (Function Expression) с набором настроек, определяющих внешний вид галереи изображений, её поведение и способы управления галерей. Эти настройки можно изменить во время инициализации галереи, заменив их значения на пользовательские.
Кроме этого, в конструкторе вызывается функция init, которая формирует галерею исходя из полученных настроек.

Конструктор принимает два аргумента:

  1. id — идентификатор галерей, инициализация которой происходит в данный момент;
  2. setup — ассоциативный массив с пользовательскими настройками.

Для того, чтобы была возможность обратиться к конструктору из вне анонимной функции, запишем функцию-конструктор, как свойство объекта Window.

Теперь рассмотрим полный JS-код конструктора:

Назначение некоторых свойств, несмотря на их краткое описание, может быть непонятно. Более подробно каждое свойство будет рассмотрено в процессе написания JS-скрипта.

Вызывать функцию-конструктор будем из HTML-страницы, для чего в конце HTML-вёрстки, перед закрывающим тегом </BODY> запишем следующий JS-код:

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

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

Т. к. все методы наследуются от своего прототипа, то их запись будет выглядеть следующим образом:

Давайте сократим эту запись, создав переменную, которая будет ссылаться на прототип Gallery, для этого в конец нашей анонимной функции добавим следующий JS-код:

Теперь запись функции будет выглядеть следующим образом:

Запуск инициализации адаптивной галереи изображений.

Инициализация галереи начинается вызовом функции init из функции-конструктора Gallery. В свою очередь, она вызывает ряд функций, которые:

  1. Объединяют дефолтные настройки адаптивной галереи изображений defaults с пользовательскими настройками setup, полученными в качестве второго аргумента. Результат помещается в объект options — это основной объект, с которым будет работать JS-скрипт галереи.
  2. Рассчитывают и формируют каркас галереи с учётом данных записанных в объект настроек options.
  3. Получают координату X каждого элемента галереи и помещает её в массив.
  4. Формируют навигацию по галерее.
  5. Устанавливают обработчики событий.

JS-код функции init:

Рассмотрим каждую функцию, вызываемую из функции init подробнее.

Объединяем дефолтные и пользовательские настройки адаптивной галереи изображений.

Функция extend заменяет значения свойств объекта defaults на значения свойств объекта setup, в котором находятся пользовательские настройки. Полученный результат записывается в объект options, принадлежащий текущему экземпляру галереи. Если бы на странице было несколько галерей, то каждому экземпляру галереи соответствовал свой объект options, содержащий индивидуальные настройки данной галереи.

Запишем в конец анонимной функции следующий JS-код:

Формируем каркас адаптивной галереи изображений.

Теперь, с учётом полученных настроек, прописанных в объекте options, и текущей ширины страницы, необходимо сформировать каркас галереи, вычислив размер окна слайдера и размеры элементов галереи.

Каркас адаптивной галереи изображений

Всеми вычислениями занимается функция setSizeCarousel. Алгоритм работы функции:

  • 1

    Получает ширину контейнера с классом slider. Этот контейнер является вьюпортом галереи — именно в нём происходит перемещение его элементов. Так как галерея должна быть адаптивной, то ширина данного контейнера зависит от размеров окна браузера.

  • 2

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

    Давайте внимательно посмотрим на рисунок.

    Последние элементы адаптивной галереи изображений

    На рисунке показаны две галереи прокрученные до конца. Для верхней галереи свойство max не применялось, индекс последнего элемента равен 11 (отсчёт индекса начинается с 0), а последним элементом, до которого возможна прокрутка, является «Element 12».
    В нижней галерее использован максимальный индекс (this.max = 12 - 3), поэтому слайдер прокрутился только до «Element 10». В результате, всё окно слайдера заполнено изображениями, и в таком варианте галерея выглядит красивее.

  • 3

    Вычисляет ширину элемента слайдера. Элемент слайдера — это контейнер <DIV> внутри которого находится изображение. Ширина элемента зависит от количества одновременно видимых элементов — свойство visibleItems, размера отступа между элементами — свойство margin и общей ширины слайдера — widthSlider.

    От ширины слайдера вычитаем сумму отступов уменьшенную на 1, т. к. отступ последнего видимого элемента не попадает в окно слайдера и полученную разность делим на количество видимых элементов.

  • 4

    Вычисляет расстояние между элементами. Это значение понадобится в дальнейшем для получения координаты X каждого элемента галереи.

  • 5

    Вычисляет ширину контейнера <div class="stage">, являющегося родителем для элементов для слайдера.

  • 6

    Используя полученные значения, задаёт стили контейнеру stage и каждому элементу слайдера.

    Встроенный в JavaScript метод bind, используется для передачи контекста вызова в цикл перебора элементов галереи.

Полный JS-код функции setSizeCarousel:

Получаем координату X каждого элемента адаптивной галереи изображений.

Теперь необходимо получить координату X каждого элемента слайдера, которые будут использоваться при листании галереи. За заполнение массива с координатами X отвечает функция setCoordinates, вызываемая из функции init. Функция простая и будет достаточно комментариев в самом коде.

Теперь мы рассмотрим формирование визуальных элементов навигации по галерее:

  1. кнопки «prev» и «next», сдвигающие слайдер на один элемент;
  2. постраничная навигация в виде точек, прокручивающая слайдер на количество элементов, указанных в свойстве visibleItems.

Запускается формирование навигации по галерее из функции init, вызовом функции initControl.
Подключение элементов навигации осуществляется путём присвоения свойствам nav и dots значения true. В рассматриваемой нами галерее, навигация кнопками разрешена по умолчанию, а разрешение постраничной навигации прописано в пользовательских настройках при вызове скрипта галереи.

Нам необходимо будет получить ряд DOM-объектов, поэтому давайте ещё раз посмотрим на HTML-вёрстку блока навигации:

Рассмотрим, какие задачи выполняет функция initControl:

  1. Получает объект контейнера с классом nav-ctrl и объект немаркированного списка с классом dots-ctrl. Эти объекты необходимы для того, чтобы показывать элементы навигации, добавляя им стиль display: block или скрывать их, удаляя этот стиль, в зависимости от значений свойств nav и dots.
    Кроме этого, на объект списка будет повешен обработчик события для управления постраничной навигацией.
  2. Получает объекты кнопок управления «prev» и «next». На них будут повешены обработчики событий для прокручивания галереи вправо / влево на один элемент.
    При помощи функции setNavStyle кнопка «prev» визуально делается неактивной, т. к. при инициализации галереи текущим устанавливается первый элемент и, соответственно, нет никаких предыдущих элементов.
  3. Вызывает функцию creatDotsCtrl, которая исходя из общего количества элементов галереи и значения свойства visibleItems заполняет список <ul class="dots-ctrl"></ul> элементами постраничной навигации. Первый элемент делает визуально активным.
    Записывает в массив координату X первого элемента каждой страницы.

Код самой функции initControl с подробными комментариями:

Функция setNavStyle управляет внешним видом кнопок «prev» и «next», делая неактивной кнопку «prev», если слайдер находится в самом начале. Если слайдер прокручен до самого конца, то неактивной будет кнопка «next». Во всех остальных случая обе кнопки выглядят активными.
Код функции очень простой:

Теперь рассмотрим, как правильно рассчитать и сгенерировать элементы постраничной навигации — ими являются элементы списка LI с вложенными в них элементами SPAN. Именно span будет определять внешний вид пагинатора и управление галереей — клик по этому элементу вызовет прокрутку слайдера.

За формирование пагинации отвечает функция creatDotsCtrl, вызываемая из функции initControl. Описание работы функции creatDotsCtrl:

Используя метод document.createElement(tag), создаются два новых элемента: LI и SPAN, после чего, при помощи метода parentElem.appendChild(elem), элемент SPAN помещается вовнутрь элемента LI.

Запускается цикл while с шагом visibleItems. При каждой итерации цикла выполняются следующие операции:

  1. Создаётся клон полученного элемента списка LI. Если это первый элемент в списке, то клону добавляется класс active.
  2. С помощью метода parentElem.appendChild(elem) клон добавляется в конец объекта dotsCtrl и в массив spots. Этот массив в дальнейшем понадобится для получения индекса элемента в списке.
  3. Рассчитывается следующую координату Х, к которой необходимо прокрутить слайдер при постраничной навигации. При расчёте используется полученный ранее максимальный индекс max.

Полный JS-код функции creatDotsCtrl:

Функция setDotsStyle управляет внешним видом элементов постраничной навигации, выделяя элемент, соответствующий группе изображений, до которых была прокручена галерея. Код функции несложный, поэтому можно обойтись комментариями в самом коде:

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

Регистрация обработчиков событий адаптивной галереи изображений

Регистрация обработчиков событий адаптивной галереи изображений осуществляется в функции registerEvents, вызываемой из функции init. Обработчик назначается вызовом метода addEventListener, который привязывается к элементу, на котором событие регистрируется.

Запомните, это очень важно.
При использовании метода addEventListener теряется контекст вызова — this, который ссылается на текущий объект. Используя встроенный в JavaScript метод bind, можно напрямую передать контекст вызова в функцию обработчика события.

Итак, инициализация и построение адаптивной галереи изображений закончены. Прежде чем рассматривать функционал её скроллинга, давайте подведём итог и кратко изложим, что было сделано:

  1. Объединены дефолтные и пользовательские настройки, на основании которых создаётся и функционирует галерея.
  2. Исходя из текущего размера окна браузера и значения свойства visibleItems получены размеры отдельных элементов галереи, слайдера и самой галереи в целом.
  3. Получены координаты X каждого элемента галереи.
  4. В соответствии с настройками, создано пошаговое и постраничное управление галереей.
  5. Установлены обработчики событий, позволяющие прокручивать галерею.

Прокрутка адаптивной галереи изображений.

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

Принцип прокручивания адаптивной галереи изображений.

У нас есть контейнер stage, в котором в одну строку размещены изображения, и являющийся дочерним элементом контейнера slider.
Контейнер slider имеет стиль overflow: hidden, в результате чего отображается только та часть stage, которая находится внутри границ slider, остальная часть будет скрыта. Ширина slider и количество отображаемых элементов зависит от значения свойства visibleItems.

Меняя позиционирование контейнера stage по горизонтали, можно отображать в области контейнера slider изображения, скрытые в данный момент. Для смещения stage будем использовать свойство transform:translateX(), а за точку отсчёта смещения возьмём левую границу контейнера slider.
Таким образом, чтобы прокрутить галерею к нужному изображению, необходимо подставить соответствующее значение в свойство transform:translateX().
Значения координат всех изображений были получены и записаны в массив coordinates при вызове функции setCoordinates.

Данный функционал реализован в двух основных функциях:

  1. getNextCoordinates — возвращает координату Х элемента, до которого должен переместиться контейнер stage;
  2. scroll — непосредственно реализует механизм прокручивания, а также изменяет визуальное отображение элементов пошаговой и постраничной навигации по мере прокручивания галереи.

Рассмотрим работу этих функций подробнее.

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

Функция принимает один аргумент — direction, имеющий два значения, определяющие направление перемещения:
-1 — переход к предыдущему элементу;
1 — переход к следующему элементу.

Кроме этого, функция использует свойства конструктора:

  1. current — индекс координаты текущего элемента;
  2. count — количество элементов в галерее;
  3. visibleItems — количество элементов отображаемых в слайдере;
  4. max — максимальный индекс, который может быть у текущего элемента.

Используя полученный аргумент и свойства конструктора, функция может накладывать ограничения на прокручивание галереи:
— попытка перейти к предыдущему элементу, когда текущим является первый элемент;
— попытка перейти к следующему элементу, когда текущий элемент имеет индекс равный max.

Запомните, это очень важно.
Ограничения на прокручивание галереи действуют при любом способе управления. В дальнейшем акцентировать внимание на них не будем, подразумевая, что они работают по-умолчанию.

Рассмотрим JS-код функции:

Реализация скроллинга адаптивной галереи изображений.

Как я писал выше, за непосредственную реализацию скроллинга отвечает функция scroll. Функция принимает два аргумента:
1. координата X, полученная функцией getNextCoordinates;
2. transition — время анимации скроллинга.

Может возникнуть резонный вопрос: зачем передавать время анимации отдельным параметром, когда оно прописано в настройках галереи и его значение есть в объекте options?
Всё упирается в постраничную навигацию. Если прокрутка будет на соседнюю страницу, то базового значения baseTransition будет достаточно. А если необходимо перейти сразу на несколько страниц или к последней странице галереи? В этом случае, при использовании значения baseTransition, изображения просто промелькнут по экрану без заметной плавности, что не очень красиво. Поэтому, при постраничной навигации значение transition рассчитывается в зависимости от того, на сколько страниц нужно проскроллить галерею. Подробнее это будет описано в разделе постраничной навигации.

При рассмотрении данной функции необходимо учесть ещё один очень важный момент — это переключение, по мере прокрутки, состояния элементов навигации из неактивного состояния в активное и наоборот. Для этого в код добавлен вызов двух функций (setNavStyle и setDotsStyle), которые будут менять стили отображения кнопок управления и элементов постраничной навигации в зависимости от текущего индекса.

Подробно описывать работу функции scroll нет необходимости — она достаточная простая, вполне хватит комментариев в JS-коде функции:

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

Управление прокруткой адаптивной галереи изображений.

Напомню, что все обработчики событий, вызывающие функции управления прокруткой галереи, находятся в функции registerEvents, рассмотренной ранее.

Автоматическая прокрутка адаптивной галереи изображений.

Для включения автоматической прокрутки, необходимо присвоить свойству autoScroll значение «true». Делается это в пользовательских настройках во время вызова функции-конструктора:

Если значение свойства autoScroll равно «true», то с помощью метода setInterval с периодичностью, заданной в свойстве interval функции-конструктора Gallery, вызывается функция autoScroll.

JS-код функции autoScroll:

Встроенные в JavaScript методы call и apply, используются для передачи контекста вызова в функции getNextCoordinates и scroll соответственно.

Управление прокруткой адаптивной галереи изображений с помощью кнопок «prev» и «next».

При нажатии на кнопку «prev» или «next» вызывается функция navControl, при этом контейнер с изображениями смещается или к предыдущему, или к следующему изображению. JS-код функции:

Постраничная прокрутка адаптивной галереи изображений с помощью пагинатора.

Управление постраничной прокруткой галереи реализовано в функции dotsControl, которая решает две задачи:

  1. получения координаты X первого изображения на странице, до которой будет прокручиваться галерея;
  2. расчёт времени, за которое галерея прокрутиться к выбранной странице, с учётом количества изображений, на которые нужно проскроллить галерею.

Для получения координаты X, функция dotsControl не обращается к функции getNextCoordinates, а использует свой алгоритм:

  1. Получает объект элемента навигации, по которому был сделан клик
  2. Находит аналогичный элемент и его индекс в массиве spots — этот массив был создан при формировании постраничной навигации и содержит все элементы пагинатора.
    Для поиска индекса элемента в массиве spots используем встроенный метод indexOf, который возвращает индекс элемента в массиве или -1, если такого индекса нет.
  3. Получает индекс изображения, до которого нужно прокрутить галерею, путём умножения индекса элемента пагинатора на значение свойства visibleItems.

Для расчёта времени анимации, используя индексы текущей и полученной координаты X, вычисляем, на сколько элементов (изображений) будет прокручена галерея. Это значение умножаем на коэффициент и прибавляем к базовому значению baseTransition.
Таким образом, время анимации будет напрямую зависеть от того, сколько страниц (количество изображений на этих страницах) необходимо прокрутить.

JS-код функции dotsControl:

Управление прокруткой адаптивной галереи изображений с помощью клавиатуры.

При таком способе управления используются клавиши «←» (влево) и «→» (вправо), имеющие виртуальные десятизначные коды 37 и 39 соответственно.
Для включения управления с помощью клавиатуры, необходимо в пользовательских настройках, во время вызова функции-конструктора, присвоить свойству keyControl значение «true». По-умолчанию установлено значение «false», т. к. при размещении нескольких галерей на одной странице, управление с клавиатуры будет всеми галереми одновременно.

Реализовано такое управление в функции keyControl. Подробно расписывать работу функции не буду — код очень простой, достаточно комментариев в самом коде.

Управление прокруткой адаптивной галереи изображений с помощью колёсика мыши.

Управление колёсиком мышки будет работать только в том случае, если курсор находится над галерей. Это обуславливается способом регистрации обработчика события.

При такой регистрации обработчика события, функция wheelControl будет вызвана, только если указатель мыши находится над DIV’ом с классом ‘slider’ конкретного экземпляра галереи — this.gallery. Такой подход обеспечивает корректное управление при любом количестве галерей на одной странице.

Для определения направления прокрутки галереи используем свойство deltaY, показывающее количество прокрученных пикселей по вертикали со знаком, соответствующим направлению прокрутки.

JS-код функции wheelControl:

Управление прокруткой адаптивной галереи изображений перетаскиванием мышью и свайпом.

Рассмотрим ещё два очень похожих способа прокручивания галереи: перетаскивание с помощью мыши и листание галереи пальцем (swipe) на мобильных устройствах. Несмотря на то, что первый способ основан на событиях мыши, а второй на touch событиях, они очень похожи и используют одни и те же функции.

Ещё раз обратимся к функции registerEvents, к той части, где регистрируются mouse events и touch event

Как видео из представленного кода, независимо от источника, события обрабатываются одними и теми же функциями:
tap, нажатие левой кнопки мыши или касание экрана пальцем;
drag, перемещением мыши или пальца по экрану;
release, отпускание кнопки мыши или палец отрывается от экрана, а также выход за пределы контейнера «slider» курсора мыши.

При работе этих функций будет требоваться информация о текущем положении курсора или пальца. Для этой цели создадим функцию xpos, которая будет возвращать координату X текущего положения курсора мыши или пальца на экране мобильного гаджета без учета прокрутки.

Работа функции «tap».

Функция tap, используя вызов функции xpos, получает координату X, с которой начато перетаскивание и устанавливает флаг нажатия.

Работа функции «drag».

Функция drag отслеживает перемещение курсора мыши или пальца по экрану и, при выполнении определённых условий, передаёт в функцию scroll разницу между текущей координатой X и смещением курсора от точки, с которой начато перетаскивание.

Остановимся подробнее на условиях, влияющих на работу функции:

  • 1

    Проверяется, выставлен ли флаг нажатия pressed. Если этот флаг проигнорировать, то функция начнёт работать и пытаться проскроллить галерею, даже когда курсор просто перемещается над ней. Результат будет непредсказуемым.

  • 2

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

  • 3

    Накладывается ограничение на прокрутку галереи в её крайних положениях.
    Допустим, галерея находится в исходном состоянии и первый её элемент является активным. При попытке перетащить её вправо, как для просмотра предыдущего изображения, галерея смещается максимум на величину указанную в свойстве options.limit, а после этого плавно возвращается в исходное состояние.

    Перетаскивание адаптивной галереи изображений

    Аналогичное поведение будет у галереи, если она прокручена до последнего элемента, но её тянут влево.

    Для реализации такого алгоритма, предварительно необходимо вычислить:

    1. Общую ширину всех невидимых в данный момент элементов слайдера:

    2. Разницу между текущей координатой и смещением курсора от точки старта, с которой начато перетаскивание:

    Полный код поведения галереи изображений в крайних положениях:

Полный JS-код функции drag:

Работа функции «release».

Функция release обрабатывает окончание пролистывания галереи изображений и начинает работу в момент, когда отпускается левая кнопка мыши или палец отрывается от экрана, а так же, когда курсор мыши или палец выходит за пределы видимой области галереи.

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

Листание адаптивной галереи изображений

На представленном рисунке показано перемещение галереи влево, при этом элемент «Element 4», являющийся текущим, сдвинут на расстояние меньше половины свой ширины. В такой ситуации, галерея открутиться назад и «Element 4» останется текущим.
Если «Element 4» сдвинуть на расстояние большее половины его ширины, то галерея прокрутиться дальше и текущим станет «Element 5».

Адаптация галереи изображений к изменению разрешения.

Адаптивность необходима для того, чтобы галерея изображений во всём диапазоне разрешений выглядела корректно, сохраняла свою функциональность и, при этом, отсутствовала горизонтальная прокрутка.
В функции setSizeCarousel реализована основа адаптивности:

  1. Ширина видимой области слайдера (viewport), в которой прокручиваются изображения, зависит от ширины страницы.
  2. Ширина элементов (изображений) рассчитывается в зависимости от размера вьюпорта и количества одновременно выводимых изображений.
  3. Ширина контейнера с классом stage зависит от рассчитанной ширины изображений.

Но для полноценной адаптивности этого недостаточно. Нужно заставить меняться настройки галереи в зависимости от разрешения экрана. Для этой цели добавим в пользовательские настройки свойство adaptive. В качестве его значения используем ассоциативный массив, ключами которого будут разрешения экрана, при которых необходимо изменить настройки галереи изображений, а значения будут представлять объекты, содержащие эти настройки, записанные в литеральной форме.

Изменим вызов функции-конструктора из HTML-страницы:

Для обработки ассоциативного массива, являющегося значением свойства adaptive и получения настроек, соответствующих текущему разрешению экрана, создадим функцию setAdaptiveOptions. Алгоритм работы функции:

  1. Создаёт массив из ключей, являющимися контрольными точками (break points).

  2. Сравнивая ширину страницы (документа) со значениями break point из массива, определяет ближайшую контрольную точку «снизу». Эта точка будет служить ключом к объекту с настройками для данного диапазона разрешений.
    Например, разрешение экрана 640px. Ближайшие к нему контрольные точки — 560 и 768. Выбрана будет 560.

  3. Считывает все свойства в объекте с полученным ключом и записывает их значения в объект options поверх существующих.

JS-код функции setAdaptiveOptions:

В результате работы функции setAdaptiveOptions, мы получили настройки галереи изображений, оптимальные для текущего разрешения.
Вызов данной функции происходит из функции setSizeCarousel, формирующей каркас галереи:

Итак, что мы имеем на данный момент. При запуске адаптивной галереи изображений, происходит её инициализация и подключаются настройки соответствующие текущему разрешению экрана монитора или мобильного гаджета. В результате, не зависимо от разрешения, галерея будет выглядеть оптимально для данного экрана.
Кажется, на этом написание скрипта можно закончить. К сожалению, есть одно но. Например, пользователь просматривал галерею на планшете или смартфоне в ландшафтном режиме, а потом повернул в портретный режим. Или другой пример, пользователь самостоятельно изменил размеры окна браузера. Что произойдёт в этом случае? Ничего. Настройки галереи останутся без изменения и, скорее всего, её просматривать станет неудобно.

Что объединяет эти два примера? И в одном, и в другом случае меняется разрешение экрана по горизонтали. Другими словами возникает событие resize. Следовательно, чтобы оптимизировать галерею под новое разрешение, необходимо назначить обработчик этому событию, который повторно запустит инициализацию галереи через вызов функции init.

Инициализация адаптивной галереи изображений при изменении разрешения экрана.

Первое, что нужно сделать — это назначить обработчик для события resize. Для этого, в самое начало функции registerEvents, регистрирующей обработчики событий, добавим следующий JS-код:

Как видно из кода, при изменении разрешения, будет вызываться функция resize. Может возникнуть вопрос, а почему сразу не вызвать функцию init и не перестроить галерею под новое разрешение? Дело в том, что необходимо запомнить, а после инициализации галереи вывести активным именно то изображение, которое было активным до изменения разрешения.

Давайте разберём алгоритм работы функции resize:

  1. Вызывает функцию init, запуская инициализацию и построение каркаса галереи изображений с учётом нового разрешения.

  2. Получает новый индекс и координату X текущего элемента. Это очень важно, когда пользователь просматривает последние изображения галереи. Давайте посмотрим на рисунок и всё станет понятно без лишних объяснений.

    Адаптивная галерея изображений
  3. Вызывает функцию scroll для докрутки галереи (при необходимости) к текущему элементу.

Для уменьшения нагрузки на браузер, обработку изменившихся параметров функция resize производит через заданный период времени, используя таймер-планировщик setTimeout.

Полный JS-код функции setTimeout:

На этом создание адаптивной галереи изображений закончено. Посмотреть пример галереи и скачать HTML-вёрстку и полный JS-код, Вы можете по ссылкам, указанным в начале страницы.

Комментарии

Всего: 10 комментариев
Требования при посте комментариев:
  1. Комментарии должны содержать вопросы и дополнения по статье, ответы на вопросы других пользователей.
    Комментарии содержащие обсуждение политики, будут безжалостно удаляться.
  2. Для удобства чтения Вашего кода, не забываейте его форматировать. Вы его можете подсветить код с помощью тега <pre>:
    <pre class="lang:xhtml"> - HTML;
    <pre class="lang:css"> - CSS;
    <pre class="lang:javascript"> - JavaScript.
  3. Если что-то не понятно в статье, постарайтесь указать более конкретно, что именно не понятно.
  • Я не знаю кто это писал, но у меня создалось впечатление, что это просто умнейший человек.

    Тут все настолько понятно описано, надо просто расставить около каждой переменной console.log, чтобы посмотреть что в нее передается и прочитать работу не понятных тебе функций.

    Но эти многабукв того определенно стоят.

    Спасибо большое!

    • Вальдемар Александр Ответить 15 марта 2019 в 21:58

      Спасибо за лестный отзыв )))
      Стараюсь все статьи писать в таком стиле.

      • Александр Вальдемар Ответить 16 марта 2019 в 12:52

        А самое прекрасное в этой галерее, помимо адаптивности, которую днем с огнем не найдешь во встроенных бутстрапах или slick слайдерах.

        Это то, что добавив в массив defaults новый параметр, например wheel

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

        Это прекрасный инструмент и я всем его советую!

  • Кое-что нашел, в функциях

    if (this.mouseDrag !== false) …
    и
    if (typeof window.ontouchstart !== ‘undefined’ && this.touchDrag !== false)…

    должно быть

    if (this.options.mouseDrag !== false)
    и
    if (typeof window.ontouchstart !== ‘undefined’ && this.options.touchDrag !== false) (не хватает options)

    И еще заметил, что этой функцией нельзя управлять в адаптиве, это происходит из-за того, что при переопределении функции, есть условие

    if(!this.events)
    {
    this.registerEvents();
    }

    тогда не срабатывает замена свойства.

    Был бы признателен за подсказку, как можно переопределять данное свойство при адаптиве, чтобы не делать костыльных условий

  • Несколько изменил скрипт, вообще отказавшись от управления разрешением на использование ‘mouse events’ и ‘touch events’. Перетаскивание мышью и свайп между собой не конфликтуют, за исключением одного момента: отрыв пальца от экрана, кроме события ‘touchend’, может вызвать событие ‘click’. Чтобы исключить это, в функциях ‘tap’, ‘drag’ и ‘release’ после строки:

    e.preventDefault();

    необходимо добавить:

    e.stopPropagation();

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

  • Добрый день Вальдемар! Подскажите пожалуйста как можно прикрепить к адаптивной галереи изображений (сейчас у меня на локальном сайте сделан fullscreen slider на весь экран — 5 слайдов) css3 свойства — blur, scale, opacity, transform scale? Дело в том, что первый слайд, загружается с означенными эффектами, а вот последующие слайды, проходят без эффектов, только скролом -вот пример эффекта, к-рый пытаюсь установить на слайды:
    /* slide opacity images — плавное появление изображения */
    .slide-opacity {
    opacity: 1;
    transition: opacity 5ms ease-in-out;
    }

    .slide-opacity {
    opacity: 0;
    }

    /* slide-blur images — blur, scale, opacity размытые изображения */
    .slide-blur {
    filter: blur(.5vw);
    transform: scale(1.075);
    }

    blur-in {
    will-change: transform, opacity;
    animation: blur-in 1s ease-in-out .5s;
    }

    @keyframes blur-in {
    0% { transform: scale(1.075); opacity: 0; }
    100% { transform: scale(1); opacity: 1; }
    }

    И второй вопрос, наверное дополняет первый. На полноэкранном слайдере, хотелось прикреплять рекламные блоки capture используя CSS3 2D Transform (https://html5book.ru/css3-transform/), допустим некий Привет! Я твой рекламный блок! )) 250х100 px, на котором размещена информация. Ваша адаптивная галерея легковесна, лаконична, просто супер! Грузить и устанавливать ради эффектов монструозные слайдеры по 1000 строк, которых с избытком в интернете, совсем уж не хочется. Буду признателен за подсказки!

    • Вальдемар Илья Ответить 28 апреля 2019 в 02:19

      Попробуйте изображение обернуть ещё в один DIV и уже к нему применять ваши классы.
      И ещё, плавное появление изображения сделайте через анимацию с использованием @keyframes.

  • почему файл в браузере открывается, а на локальном сервере видно только «Aдаптивная галерея изображений» и «prev next» …не запускается js-код или не подключены стили? как исправить?

  • Здравствуйте. Сделайте, пожалуйста, урок с подгружающимися изображениями. Где при открытии страницы существуют только два слайда. Первый слайд на виду, а второй скрыт. При прокрутке на второй слайд, подгружается третий слайд, если информация о нем есть в базе. И так далее, пока изображения не закончатся.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *