📜 ⬆️ ⬇️

How I did a really adaptive slider (carousel)

Good day, dear readers and writers!


Today I will tell you how the project faced me with the task of manufacturing an adaptive slider and what came of it


About the article and for whom it is


I am writing this article not so much because I want to get a community response to solving this problem, but also because solving the questions of the article seems fundamental to me to understand the adaptability of the slider on the web. If someone has already written such components, please respond and share similar experiences


A little bit about what happened and what tools were used


In the React application, you need to make a carousel (hereinafter I will use this name), the elements of which harmoniously look on the screen of any size. There are several limitations:


  1. The maximum width of an element is 150 px
  2. Tool Used - React Owl Carousel
  3. The maximum size of the container for the carousel is 1190 px
  4. There are also indicators of the padding property for different screens (affects the width of the visible part of the container) and margin (between elements at least 5 pixels)
  5. The carousel should go in cycles
    And other conditions that do not affect the subject of the article

Digression on the mechanics of the carousel


Many carousels (React Owl Carousel is not an exception) use the special active class to show which describes the elements that are currently displayed on the screen.


To display an infinite loop on the screen, the first and last elements are duplicated (the mechanics and problems of this dubbing are a topic for a separate article).


Properties are described by special objects, we will be interested in the responsive object, which is responsible for the reassignment of properties.


The rest of the data on the mechanics of work will be clear as the solution is described.


First problems


At first everything went smoothly - the elements themselves were written and stylized, the basic properties of the entire carousel were spelled out. Problems started when setting property {loop: true}


The carousel is looping inadequately


When scrolling to the end of the list, free space remained in the carousel and for some time it was it that was scrolling.


The reason was the maximum width of the element, not consistent with their number. A concrete example is the width of the container 1190 px, with the number of elements set to 3.


In other words, the carousel expects 3 elements to stretch to 1190px, and they cannot become larger than 150px.


Increasing the number of items


The problem takes on a different angle: if there are too many elements per container, their width becomes too small (and there is content inside them!) If I set the min-width property, then on some screen sizes the elements crawl onto each other, ignoring the margin, which violates the conditions .


We summarize the adaptability conditions


  1. The number of elements on the screen should be less than the ratio of screen size to
    minimum width of the element - otherwise even elements of the minimum width will not fit on the screen.
  2. The ratio of the screen size to the estimated number of elements should not exceed the maximum estimated length, otherwise there is a problem with looping.
  3. The conditions described above must be met for any screen size (from 330px to 1190px).

We solve the problem as programmers


If you approach the problem sequentially, it is obvious that you have to give up something, in my case it was the minimum width of the element.


What should be the minimum width of the element so that for all container screens the adaptability conditions are met?


//       const getBackTrace = (minScreen = 300, maxElementWidth = 150) => { let backTrace = {} for (let minElementWidth = maxElementWidth; minElementWidth > 0; minElementWidth--){ //            //     backTrace for(let screen = minScreen; screen <= 1100; screen++){ let elementCount = screen / minElementWidth | 0 if((screen / elementCount) > maxElementWidth){ backTrace[minElementWidth] = screen break } } } for(let key in backTrace){ //        ,      if (backTrace[key - 1] == undefined){ backTrace.result = key - 1 return backTrace } } } // getBackTrace(300, 150).result = 100 

The result in 100px did not suit me, since it does not allow me to fit all the content in the element. Therefore, we continue the search until we find the right value and look for what else you can sacrifice.


Remember the subtitle? To search, write a function


 const getMinScreen = (minWidth = 300, maxWidth = 767, maxElementWidth = 150) => { let research = [] //  ,          // getBackTrace,       for(let min = minWidth; min < maxWidth; min++){ let { result } = getBackTrace(min, maxElementWidth) research.push({result, min}) } //          "  "  return research .reduce((acc, curr, idx, arr) => { let obj = {} let {min, result} = curr obj[min] = result if(idx == 0) return obj if(arr[idx-1].result == result){ return {...acc} } else { return {...acc, ...obj} } }, {}) } /* Returned object {300: 100, 303: 101, 306: 102, 309: 103, 312: 104, 315: 105, 318: 106, 321: 107, 324: 108, 327: 109, 330: 110, 333: 111, 336: 112, 452: 113, 456: 114, 460: 115, 464: 116, 468: 117, 472: 118, 476: 119, 480: 120}   480    */ 

Considering the obtained object, a big leap is seen when moving from 336px to 452px.
I made a strong-willed decision to limit adaptability to 36px.


We describe the adaptive object


It would seem that the problem has been solved, but such a solution only proves that compliance with the conditions is possible for screens from 336px, but does not describe the method. But there are different conditions that limit me in the production of an object with adaptability properties
Having accepted for myself that the minimum width of an element without losses can be 107 px, varying the margin value, I came to the following indicators:


Screenmarginminimum width
336+five107
468+ten107
763+15112

The only thing left is to collect the received data in a heap and implement the adaptive object:


 getResponsiveOwlItems = () => { let responsive = {}; responsive[0] = {items: 2, nav: false} // 112 = 107 (minimal div) + 5 (margins) let itemMinWidthReference = 112; const getOneWidth = deviceWidth => deviceWidth / itemMinWidthReference | 0 // 1190 - container width for(let i = itemMinWidthReference * 3 + 20; i <= 1190; i += itemMinWidthReference){ // .container padding > 768 90px + padding 90(.container) // .container padding < 768 40px + padding -40(.container) // +20px stagePadding let padding = i > 767 ? 200 : 20 if(i > (468 + padding)) { itemMinWidthReference = 117 } if(i > (767 + padding)) { itemMinWidthReference = 127 } let items = getOneWidth(i - padding) let nav = i > 700 ? true : false let margin = 5; if (i > 468){ margin = 10 } if (i > 767){ margin = 15 } responsive[i.toString()] = {items, nav, margin} //      itemMinWidthReference i = i - (i % itemMinWidthReference) + 1 } return responsive; } 

On the day of publication, everything looks logical, and I could not reproduce the error in the carousel - everything probably works as intended.


Thank you for your attention, waiting for your comments and comments!


')

Source: https://habr.com/ru/post/461525/


All Articles