Last Updated:

Adaptive image gallery for the site in JavaScript

In this article, I will tell you how to create an adaptive gallery starting with HTML layout and ending with JavaScript, connect animation effects to it and various ways to control scrolling, including using swipe.

Table of Contents

Intro.

The image gallery becomes an integral part of any site and, especially, selling a landing page. 

To begin with, we will draw up a technical task for creating an adaptive image gallery:

  1. The gallery should be adaptive and should work correctly on any device with a resolution of 320px and above.
  2. To manage image galleries, we use the maximum possible options:
    — navigation buttons "prev" and "next";
    - pagination;
    – keyboard keys with arrows "right" and "left";
    – rotation of the mouse wheel;
    - Drag with the mouse cursor;
    – on mobile devices, swipe with a finger (swipe);
    — automatic scrolling of the gallery.
  3. The following navigation methods can be combined, plugged in, or disabled as needed.
  4. Dragging to the next image occurs if the image has been moved at least 50% of its width. Otherwise, the slider will smoothly return to the current image.
  5. It is possible to connect an animation module to the image gallery to create animation effects when changing the image.

HTML-layout of the adaptive image gallery.

First, I will present you with the HTML layout of the image gallery, and then I will comment on it.

Let us consider in more detail the purpose of the containers and blocks of which the gallery consists:

div.gallery
The parent gallery container. The attribute contains the name of the object with the gallery settings.data-setting
div.slider
Determines the size of the visible part of our adaptive gallery. The number of simultaneously displayed images in this container is determined in the tinctures.
div.stage
This container contains all the elements of the image gallery. By changing its positioning relative to the parent element, we will get a scrolling gallery.
div.control
Contains control for turn-by-turn and page-by-page navigation.
div.nav-ctrl
Controls located in a container are responsible for scrolling the gallery one step (one image). You can remove text from these elements, place them to the right and left of the gallery, and display right and left arrows in them using background images. No change in layout is required, just make changes to the style sheet.
div.dots-ctrl
An unlabeled list that contains page-by-page navigation items. They are generated by the script depending on the settings of the image gallery.

There are a couple of simplifications in the layout that do not affect the performance of the gallery, but it makes no sense to dwell on them in detail within the framework of this article - this is a separate topic.

  1. When you click on the image, its full-size version will not be opened.
  2. In the HTML layout, the code of elements of both step-by-step and page-by-page navigation is immediately present. It would be enough to insert only their parent element into the layout - , and create the navigation itself "on the fly" using JavaScript, depending on the settings of the image gallery.<div class="control">

The style sheet for the adaptive image gallery.

Only styles that relate directly to the gallery itself are presented.

Very important.
To reduce the size of the style sheet, I will not list properties with vendor prefixes that provide cross-browser compatibility. Do not forget to prescribe them when implementing your projects.

Initialize the adaptive image gallery.

The first thing we will do is create an anonymous self-starting function, within which our code will be located.
It is necessary to make it a rule to limit the scope of the script in order to exclude conflicts with other JS scripts connected to the page.

When writing a JS script, we will use the Class construct. This will create multiple instances of the image gallery on a single page.

Create instances of the adaptive image gallery.

First of all, let's create a collection of galleries that are located on the page. Next, using the method, we will go through the resulting collection, while we will perform the following actions:
- define the settings option for this gallery;
- Create an instance of the current gallery using the constructor of the .for...ofGallery

We will write all further JS code inside the .class Gallery { ... }

First of all, consider the constructor of the . The constructor initializes a number of objects and variables that contain information about the gallery instance. As an argument, the constructor takes the adaptive gallery object that is currently being instantiated, as well as an object with individual gallery settings.Gallery

Static properties and methods of adaptive image gallery.

In addition to the objects and variables initialized in the constructor, the class contains a number of static properties, constants, and methods.
Static properties include an object with default settings. Constants contain the code for the left arrow and right arrow keys.
Static methods refer to the class itself, not to its instances and objects. We will use two static methods:Gallerydefaults

extend()
merges and overwrites the values of two objects and produces an overall result
xpos()
returns the x-coordinate of the current position of the cursor or finger

Start initializing the adaptive image gallery.

Initializing the gallery begins by calling a function from the constructor of the . In turn, it calls a number of functions that:initGallery

  1. Combine the default settings of the adaptive image gallery with the custom settings obtained as the second argument. The result is placed in an object, which is the main object that the JS script of the gallery will work with.defaultssetupoptions
  2. Calculate and form the frame of the gallery taking into account the data recorded in the settings object.options
  3. Get the coordinate of each gallery element and place it in an array.X
  4. Form the navigation of the gallery.
  5. Install event handlers.

Function code and comments to it:init

Let's take a closer look at each function called from a function.init

Combine the default and custom settings of the adaptive image gallery.

The Static Function replaces the property values of the object with the property values of the object in which the custom settings reside. The result is written to an object that belongs to the current gallery instance. If there were multiple galleries on the page, each gallery instance would have its own object containing the individual settings of that gallery.
The JS code for the function was introduced earlier.extenddefaultssetupoptionsoptions

Form the skeleton of the adaptive image gallery.

Now, taking into account the received settings prescribed in the object , and the current width of the page, you need to form a frame of the gallery, calculating the size of the slider window and the dimensions of the gallery elements.options

 

All calculations are handled by the function . The algorithm of the function:setSizeCarousel

  • 1

    Gets the width of the container with the class . This container is the viewport of the gallery - it is in it that its elements are moved. Since the gallery must be adaptive, the width of this container depends on the size of the browser window.slider

  • 2

    The maximum index that the current element can have is calculated so that on the last page of the gallery, when using the paginator, the number of elements equal to .visibleItems

    Let's take a close look at the picture.

    Recent elements of the adaptive image gallery

    The figure shows two galleries scrolled to the end. For the upper gallery, the property was not applied, the index of the last element is 11 (the index starts at 0), and the last element to which scrolling is possible is "Element 12".
    The lower gallery uses the maximum index (), so the slider scrolled only to "Element 10". As a result, the entire slider window is filled with images, and in this version the gallery looks more beautiful.maxthis.max = 12 - 3

  • 3

    Calculates the width of the slider element. A slider element is a container inside which the image is located. The width of an element depends on the number of simultaneously visible elements — property , the size of the indent between elements — property and the total width of the slider — .<DIV>visibleItemsmarginwidthSlider

    From the width of the slider, subtract the amount of indentation reduced by 1, because the indentation of the last visible element does not fall into the slider window and divide the resulting difference by the number of visible elements.

  • 4

    Calculates the distance between elements. You will need this value later to get the coordinates of each gallery item.X

  • 5

    Calculates the width of the container that is the parent for the elements for the slider.<div class="stage">

  • 6

    Using the received values, it sets styles for the container and each element of the slider.stage

The full code of the function and comments to it:setSizeCarousel

We get the X-coordinate of each element of the adaptive image gallery.

 

Now you need to get the coordinates of each slider element that will be used when flipping through the gallery. The function called from the function . The function is simple and there will be enough comments in the code itself.XsetCoordinatesinit

Now we will look at the formation of visual elements of gallery navigation:
1. "prev" and "next" buttons, shifting the slider by one element;
2. Page navigation in the form of dots, scrolling the slider by the number of elements specified in the property.visibleItems

The formation of the gallery navigation from the function is started by calling the function .
You connect navigation elements by assigning a value to . In the gallery we are considering, button navigation is allowed by default, and the permission for page-by-page navigation is spelled out in the user settings.initinitControldata-hiddenfalsesetup

We'll need to get a number of DOM objects, so let's take another look at the HTML layout of the navigation box:

Consider what tasks the function performs:initControl

  1. Gets a container object with a class and an unlabeled list object with a class. These objects are required to show navigation elements by setting the attribute value in or hiding them by changing the value to , depending on the property values and in the adaptive gallery settings.
    In addition, an event handler will be hung on the list object to control page-by-page navigation. nav-ctrldots-ctrldata-hiddenfalsedata-hiddentruenavdots
  2. Gets the objects of the "prev" and "next" control buttons. Event handlers will be hung on them to scroll the gallery right/left on a single element.
    With the help of the function, the "prev" button is visually made inactive, because when the gallery is initialized, the first element is set to the current one and, accordingly, there are no previous elements. setNavStyle
  3. Calls the function , which, based on the total number of gallery items and the property value, populates the list with page-by-page navigation elements. The first element makes visually active.
    Writes to an array the coordinate of the first element of each page.creatDotsCtrlvisibleItems<ul class="dots-ctrl"></ul>X

The code of the function itself with detailed comments:initControl

The function controls the appearance of the "prev" and "next" buttons, making the "prev" button inactive if the slider is at the very beginning. If the slider is scrolled to the very end, then the "next" button will be inactive. In all other cases, both buttons appear to be active.
The function code is very simple:setNavStyle

Now let's look at how to correctly calculate and generate page-by-page navigation elements— they are list items. It will determine the appearance of the paginator and gallery control - clicking on this element will cause the slider to scroll.LILI

For the formation of pagination is responsible for the function , called from the function . The function, using the , method, creates a new element. Next, a loop is started with the step . At each iteration of the loop, the following operations are performed:creatDotsCtrlinitControldocument.createElement(tag)LIwhilevisibleItems

  1. A clone of the resulting list item is created. If this is the first item in the list, the clone is added to the class . LIactive
  2. The clone is added to the end of the object and to the array. You will need this array later to get the index of the item in the list. parentElem.appendChild(elem)dotsCtrlspots
  3. The following X coordinate is calculated, to which it is necessary to scroll the slider during page-by-page navigation. The calculation uses the previously obtained maximum index . max

Function code and comments to it:creatDotsCtrl

The function controls the appearance of page navigation elements by highlighting the element corresponding to the group of images to which the gallery has been scrolled. The function code is simple, so you can get by with comments in the code itself:setDotsStyle

So, we have an instance of the adaptive gallery, formed in accordance with the default and user settings, formed and configured navigation for this particular instance of the image gallery. Now you need to register event handlers that are specific to the same gallery.

Registering Adaptive Image Gallery event handlers

Adaptive Image Gallery event handlers are registered in a function called from the . The handler is assigned by calling a method that binds to the element on which the event is logged.registerEventsHandlerinitaddEventListener

Remember, this is very important.
When you use the method, you lose the call context - , which refers to the current object. Using the built-in JavaScript method, you can directly pass the call context to the event handler function. addEventListenerthisbind

So, the initialization and construction of the adaptive image gallery is finished. Before looking at the functionality of its scrolling, let's summarize and summarize what was done:

  1. Default and user settings are combined, on the basis of which the gallery is created and functions.
  2. Based on the current size of the browser window and the property value, the sizes of the individual elements of the gallery, the slider and the gallery as a whole are obtained.visibleItems
  3. The X coordinates of each gallery element are obtained.
  4. In accordance with the settings, a step-by-step and page-by-page management of the gallery has been created.
  5. Event handlers have been installed that allow you to scroll through the gallery.

Scroll through the adaptive image gallery.

First of all, we will consider the functions that directly implement the scrolling mechanism of the adaptive photo gallery, and only then the options for calling them, depending on the way you control the scroll.

The principle of scrolling through the adaptive image gallery.

We have a container that contains images on a single line, and is a child of the container.
The container has a style that causes only the part that is inside the borders to be displayed, the rest of which will be hidden. The width and number of items displayed depend on the value of the .stagesliderslideroverflow: hiddenstagesliderslidervisibleItems

By changing the horizontal positioning of the container, you can display images that are currently hidden in the container area. For displacement, we will use the property , and for the point of reference of displacement, let's take the left border of the container .
Thus, to scroll the gallery to the desired image, you must substitute the appropriate value in the .
The coordinate values of all the images were retrieved and written to the array when the function .stagesliderstagetransform:translateX()slidertransform:translateX()coordinatessetCoordinates

This functionality is implemented in two main functions:

  1. getNextCoordinates is the X-coordinate of the element to which the container should move stage;
  2. scroll – directly implements the scrolling mechanism, and also changes the visual display of step-by-step and page-by-page navigation elements as the gallery scrolls.

Let's take a closer look at how these features work.

Get the coordinate to which the adaptive image gallery should scroll.

The function takes a single argument, , which has two values that determine the direction of movement:
-1 is the transition to the previous element;
1 - Move to the next item.direction

In addition, the function uses the properties of the constructor:

  1. current — index of the coordinate of the current item;
  2. count — the number of elements in the gallery;
  3. visibleItems — the number of items displayed in the slider;
  4. max is the maximum index that the current item can have.

Using the resulting argument and constructor properties, the function can impose restrictions on scrolling through the gallery:
- attempting to jump to the previous element when the current element is the first element;
is an attempt to move to the next item when the current item has an index of .max

Remember, this is very important.
Gallery scrolling restrictions apply to any control method. In the future, we will not focus on them, implying that they work by default.

Function code and comments to it:getNextCoordinates

Implement scrolling of the adaptive image gallery.

As I wrote above, the function of . The function takes two arguments:
1. the x-coordinate obtained by the function ;
2. transition — scroll animation time.scrollgetNextCoordinates

A reasonable question may arise: why pass the animation time as a separate parameter, when it is prescribed in the gallery settings and its value is in the object?
It all comes down to page-by-page navigation. If you scroll to the next page, the base value will be enough. What if you need to go to several pages at once or to the last page of the gallery? In this case, when using the value , the images will simply flash across the screen without noticeable smoothness, which is not very beautiful. Therefore, in page-by-page navigation, the value is calculated depending on how many pages you want to scroll through the gallery. This will be described in more detail in the page navigation section.optionsbaseTransitionbaseTransitiontransition

When considering the function, it is necessary to take into account another very important point - this is the switching, as you scroll, the state of navigation elements from inactive to active and vice versa. To do this, the code has added a call to two functions ( and ), which will change the display styles of the control buttons and page-by-page navigation elements depending on the current index.scrollsetNavStylesetDotsStyle

There is no need to describe in detail the work of the function - it is quite simple, the comments in the JS-code of the function will suffice:scroll

Function code and comments to it:scroll

After understanding how the gallery scrolling mechanism works, you can proceed to the consideration of various options for controlling this scrolling.

Control the scrolling of the adaptive image gallery.

As a reminder, all event handlers that call gallery scroll control functions are in the function discussed earlier.registerEventsHandler

Automatic scrolling of the adaptive image gallery.

To enable automatic scrolling, you must set the property to true. This is done in the user settings - object . If autoscroll is enabled, the function is called using the method with the frequency specified in the static property property property.autoScrollsettingsetIntervalintervaldefaultsautoScroll

Control the scrolling of the adaptive image gallery using the "prev" and "next" buttons.

When you click on the "prev" or "next" button, the function . The scrolling direction of the gallery is determined by the value of the data attribute. Depending on its value, the container with images is shifted to either the previous or the next image.navControldata-shiftstage

Function code and comments to it:navControl

Page-by-page scroll through the adaptive image gallery using a paginator.

Controlling the page-by-page scrolling of the gallery is implemented in a function that solves two problems:dotsControl

  1. Get the X-coordinate of the first image on the page to which the gallery will scroll.
  2. calculation of the time in which the gallery will scroll to the selected page, taking into account the number of images on which you need to scroll through the gallery.

To obtain the X coordinate, the function does not access the function , but uses its own algorithm:dotsControlgetNextCoordinates

  • 1

    Gets the object of the navigation element that was clicked on.

  • 2

    Finds a similar element and its index in the array — this array was created when the page-by-page navigation was formed and contains all the elements of the paginator.
    To find the index of an element in an array, use the built-in method , which returns the index of the element in the array, or -1 if there is no such index.spotsspotsindexOf

  • 3

    Gets the index of the image to scroll to by multiplying the index of the paginator element by the value of the property .visibleItems

To calculate the animation time, using the indices of the current and obtained X coordinates, we calculate by how many elements (images) the gallery will be scrolled. Multiply this value by a factor and add it to the base value.
Thus, the animation time will directly depend on how many pages (the number of images on these pages) need to be scrolled.baseTransition

Function code and comments to it:dotsControl

Control scrolling of the adaptive image gallery using the keyboard.

With this method of control, the keys "←" (left) and "→" (right) are used, having virtual ten-digit codes 37 and 39, respectively.
To enable keyboard control, you must set the property to "true" in the user settings. By default, the value is set to "false", because when placing several galleries on one page, keyboard control will be all galleries at the same time.settingkeyControl

This control is implemented in the . I will not describe the work of the function in detail - the code is very simple, there are enough comments in the code itself.keyControl

Control the scrolling of the adaptive image gallery using the mouse wheel.

Mouse wheel control will only work if the cursor is above the galleries. This is due to the way the event handler is registered.

With this registration of the event handler, the function will be called only if the mouse pointer is over a DIV with the 'slider' class of a specific gallery instance - . This approach provides correct management for any number of galleries on one page.wheelControlthis.gallery

To determine the scrolling direction of the gallery, use the property , which shows the number of pixels scrolled vertically with a sign corresponding to the direction of scrolling.deltaY

Function code and comments to it:wheelControl

Control the scrolling of the adaptive image gallery by dragging and swiping.

Let's look at two more very similar ways to scroll through the gallery: dragging with the mouse and swipe the gallery with your finger (swipe) on mobile devices. Despite the fact that the first method is based on mouse events, and the second on touch events, they are very similar and use the same functions.

Let's turn again to the function , to the part where mouse events and touch event are registered.registerEventsHandler

Like the video from the presented code, regardless of the source, events are handled by the same functions:

tap
Press the left mouse button or touch the screen with your finger.
drag
Move your mouse or finger across the screen.
release
releasing the mouse button or the finger is lifted away from the screen, as well as leaving the "slider" container of the mouse cursor.

These features will require information about the current position of the cursor or finger. For this purpose, we have a static function that returns the X-coordinate of the current position of the mouse or finger cursor on the screen of the mobile gadget without taking into account scrolling.
Let me remind you of the function's JS code:xpos

The "tap" function works.

The function, using a function call, gets the X coordinate from which the drag and drop is started and sets the click flag.tapxpos

The "drag" function works.

The function tracks the movement of the mouse cursor or finger on the screen and, under certain conditions, transmits to the function the difference between the current X coordinate and the cursor offset from the point from which the drag is started.dragscroll

Let us dwell in more detail on the conditions affecting the operation of the function:

  • 1

    Checks whether the click flag is set. If you ignore this flag, the function will start working and try to scroll through the gallery, even when the cursor just moves over it. The result will be unpredictable.pressed

  • 2

    Having received the displacement of the mouse or finger cursor from the initial position, check its size and, if it is less than three pixels, the function stops its work. This eliminates the accidental displacement (shaking) of the mouse or finger cursor.shift

  • 3

    There is a restriction on scrolling the gallery in its extreme positions.
    Let's say a gallery is in its original state and its first element is active. When you try to drag it to the right, as if you wanted to view the previous image, the gallery is shifted by a maximum of the amount specified in the property , and then smoothly returns to its original state.options.limit

     

    A gallery will have a similar behavior if it is scrolled to the last element, but it is pulled to the left.

    To implement such an algorithm, it is first necessary to calculate:

    1. The total width of all currently invisible slider elements:

    2. The difference between the current coordinate and the cursor offset from the starting point from which the drag is started:

    The complete code for the image gallery behavior at extremes:

The full code of the function and comments to it:drag

The "release" function works.

The function handles the end of scrolling through the image gallery and starts working at the moment when the left mouse button is released or the finger is lifted away from the screen, as well as when the mouse cursor or finger goes beyond the visible area of the gallery.release

The user's scrolling through the gallery can be interrupted at any time, and it is not necessary that the shift was made by a distance multiple of the width of the image. In such a situation, it is necessary to determine in which direction it is necessary to twist the gallery to the nearest element.

 

The following illustration shows the gallery moving to the left, with the element "Element 4", which is the current one, shifted by a distance less than half of its width. In such a situation, the gallery will return to its original position and "Element 4" will remain current.
If "Element 4" is moved by a distance of more than half of its width, then the gallery will scroll further and the current will become "Element 5".

Adapt the image gallery to change the resolution.

Adaptability is necessary to ensure that the image gallery in the entire range of resolutions looks correct, retains its functionality and, at the same time, there is no horizontal scrolling.
The function implements the basis of adaptability:setSizeCarousel

  1. The width of the viewport in which images scroll depends on the width of the page.
  2. The width of the elements (images) is calculated depending on the size of the viewport and the number of simultaneously displayed images.
  3. The width of the class container depends on the calculated width of the images.stage

But for full adaptability, this is not enough. You need to force the gallery settings to change depending on the screen resolution. For this purpose, let's add the . As its value, we use an associative array, the keys of which will be the screen resolutions at which it is necessary to change the settings of the image gallery, and the values will represent objects containing these settings, recorded in literal form.adaptive

Object code and comments to it:adaptive

To process the associative array that is the value of the property and get the settings corresponding to the current screen resolution, let's create a function. The algorithm of the function:adaptivesetAdaptiveOptions

  1. Creates an array of break points.

  2. By comparing the width of the page (document) with the break point values from the array, it determines the nearest checkpoint "from below". This point will serve as the key to the object with settings for this permission range.
    For example, the screen resolution is 640px. The closest checkpoints to it are 560 and 768. Selected will be 560.

  3. Reads all the properties in the object with the received key and writes their values to the object on top of the existing ones.options

Function code and comments to it:setAdaptiveOptions

As a result of the function , we got the image gallery settings that are optimal for the current resolution. The call to this function comes from the function that forms the frame of the gallery:setAdaptiveOptionssetSizeCarousel

So here's what we have at the moment. When you launch the adaptive image gallery, it is initialized and the settings corresponding to the current screen resolution of the monitor or mobile gadget are connected. As a result, regardless of the resolution, the gallery will look optimal for this screen.
It seems that this is where you can finish writing the script. Unfortunately, there is one but. For example, the user viewed the gallery on a tablet or smartphone in landscape mode, and then turned into portrait mode. Or another example, the user independently resized the browser window. What happens in this case? No problem. Gallery settings will remain unchanged and, most likely, it will become inconvenient to view it.

What do these two examples have in common? In both cases, the screen resolution changes horizontally. In other words, an event occurs. Therefore, to optimize the gallery for the new permission, you must assign a handler to this event that will re-initiate the initialization of the gallery through a call to the .resizeinit

Initialize the adaptive image gallery when the screen resolution changes.

 

The first thing to do is to assign a handler to the . To do this, at the very beginning of the function that registers event handlers, add the following JS code:resizeregisterEventsHandler

As you can see from the code, when you change the resolution, the . The question may arise, why not immediately call the function and rebuild the gallery to the new resolution? The fact is that you need to remember, and after initializing the gallery, display active exactly the image that was active before the resolution was changed.resizeinit

Let's look at the algorithm of the function:resize

  1. Calls the function , starting to initialize and frame the image gallery with the new resolution in mind.init

  2. Gets the new index and X-coordinate of the current item. This is very important when the user is viewing the latest gallery images. Let's look at the picture and everything will become clear without unnecessary explanations.

     
  3. Calls a function to extend the gallery (if necessary) to the current item.scroll

To reduce the load on the browser, the function processes the changed parameters after a specified period of time using the scheduler.resizesetTimeout

The full code of the function and comments to it:resize

This completes the creation of the adaptive image gallery. You can see a sample gallery and download html-layout and full JS-code, you can follow the links indicated at the beginning of the page.