Как создать круговое поле прокрутки с помощью JavaScript / CSS?

#javascript #jquery #html #css #scroll

#javascript #jquery #HTML #css #прокрутка

Вопрос:

Я хочу воссоздать круговое поле прокрутки, как показано на GIF ниже,

введите описание изображения здесь

Я не думаю, что есть какая-то причина, если возможно создание кругового поля прокрутки с использованием css, поэтому я подумал о добавлении padding-left к каждому дочернему элементу ul , чтобы поле прокрутки выглядело круглым.

Для достижения этой цели,
добавьте отступ 0px в li-1,
добавьте отступ 2px в li-2,
добавьте отступ 4px в li-3,
добавьте отступ 6px в li-4,
добавьте отступ 8px в li-5,
добавьте отступ 6px в li-6,
добавьте отступ 4px в li-7,
добавьте отступ 2px в li-8,
добавьте отступ 0px в li-9

при прокрутке отступ может быть изменен, чтобы добавить отступ 0px к li-2,
добавить отступ 2px к li-3,
добавить отступ 4px к li-4,
добавить отступ 6px к li-5,
добавить отступ 8px к li-6,
добавить отступ 6px к li-7,
добавить отступ 4px к li-8,
добавить отступ 2px к li-9,
добавить заполнение от 0 пикселей до li-10 и так далее…

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

Мой код на данный момент:

 var scrollBox = $(".circularScrollbox"),
  num = $(".scrollboxList li").length,
  vjListItem = $(".vjListItem"),
  max = num * 3,
  padding = 0,
  currentPadding = padding,
  scrollPos = scrollBox.scrollTop();

scrollBox.scroll(function() {
  if (scrollPos < scrollBox.scrollTop() amp;amp; currentPadding < max) {
    currentPadding  = 2;
    vjListItem.css("padding", "0 0 0 "   currentPadding   "px");
  } else if (scrollPos > scrollBox.scrollTop() amp;amp; currentPadding > padding) {
    currentPadding -= 2;
    vjListItem.css("padding", "0 0 0 "   currentPadding   "px");
  }
  if (scrollBox.scrollTop() == 0) vjListItem.css("padding", padding   "px");
  scrollPos = scrollBox.scrollTop();
});  
 body {
  display: flex;
  flex-direction: column;
  height: 95vh;
  justify-content: center;
  align-items: center;
  background: #222;
  color: #eee;
  font-family: 'Ubuntu Mono', monospace;
}

.circularScrollbox {
  width: 200px;
  height: 10.6em;
  padding: 0 2em;
  overflow-Y: scroll;
  background: #161616;
  border: 2px solid aqua;
}

.circularScrollbox>ol {
  list-style-type: none;
  padding-left: 0;
}  
 <head>
  <link href="https://fonts.googleapis.com/css?family=Ubuntu Mono" rel="stylesheet">
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>

<body>
  <div class='circularScrollbox'>
    <ol class='scrollboxList'>
      <li class="vjListItem">Item 01</li>
      <li class="vjListItem">Item 02</li>
      <li class="vjListItem">Item 03</li>
      <li class="vjListItem">Item 04</li>
      <li class="vjListItem">Item 05</li>
      <li class="vjListItem">Item 06</li>
      <li class="vjListItem">Item 07</li>
      <li class="vjListItem">Item 08</li>
      <li class="vjListItem">Item 09</li>
      <li class="vjListItem">Item 10</li>
      <li class="vjListItem">Item 11</li>
      <li class="vjListItem">Item 12</li>
      <li class="vjListItem">Item 13</li>
      <li class="vjListItem">Item 14</li>
      <li class="vjListItem">Item 15</li>
      <li class="vjListItem">Item 16</li>
      <li class="vjListItem">Item 17</li>
      <li class="vjListItem">Item 18</li>
      <li class="vjListItem">Item 19</li>
      <li class="vjListItem">Item 20</li>
      <li class="vjListItem">Item 21</li>
      <li class="vjListItem">Item 22</li>
      <li class="vjListItem">Item 23</li>
      <li class="vjListItem">Item 24</li>
      <li class="vjListItem">Item 25</li>
      <li class="vjListItem">Item 26</li>
      <li class="vjListItem">Item 27</li>
      <li class="vjListItem">Item 28</li>
      <li class="vjListItem">Item 29</li>
      <li class="vjListItem">Item 30</li>
      <li class="vjListItem">Item 31</li>
      <li class="vjListItem">Item 32</li>
      <li class="vjListItem">Item 33</li>
      <li class="vjListItem">Item 34</li>
      <li class="vjListItem">Item 35</li>
      <li class="vjListItem">Item 36</li>
      <li class="vjListItem">Item 37</li>
      <li class="vjListItem">Item 38</li>
      <li class="vjListItem">Item 39</li>
      <li class="vjListItem">Item 40</li>
    </ol>
  </div>
</body>  

Я уверен, что чрезмерно усложняю проблему заполнением и прочим. Есть ли более простой способ достижения этого эффекта?

Ответ №1:

Для каждого элемента в списке количество отступов зависит от:

  1. Его положение в поле
  2. Насколько сильно прокручивается поле
  3. И из-за «круговой» вещи, насколько велико поле

С помощью jQuery $item.offset().top отображается Y-позиция элемента на странице.
Это включает прокрутку, поэтому значение уменьшается по мере прокрутки поля.

Теперь $item.offset().top - $box.offset().top для положения относительно верхней части поля.
Если вы прокрутили поле так, что элемент 23 находится вверху, его значение будет равно 0, а значением любого элемента, находящегося внизу (но все еще видимого), будет высота поля.

Итак, разделите на высоту: ($item.offset().top - $box.offset().top) / $box.height()

Каждый (видимый) элемент теперь имеет значение от 0 до 1, которое сообщает вам, находится ли он в данный момент вверху поля, внизу или где-то посередине !

Затем вы можете использовать тригонометрическую функцию следующим образом: Math.sin(value*Math.PI) * maxPadding

Рабочий пример

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

1. Привет @jean-alphonse, можем ли мы повторить этот пункт меню?

Ответ №2:

Вот решение, основанное на CSS и всего нескольких JS. Хитрость заключается в том, shape-outside чтобы иметь кривую, а JS будет использоваться только для регулировки положения фигуры при прокрутке.

Это очень простой метод, но вам нужно обратить внимание на поддержку браузера (https://caniuse.com/#feat=css-shapes)

 var shape = document.querySelector(".left");

document.querySelector(".circularScrollbox").onscroll=function() {
   shape.style.marginTop = this.scrollTop "px";
};  
 body {
  display: flex;
  flex-direction: column;
  height: 95vh;
  justify-content: center;
  align-items: center;
  background: #222;
  color: #eee;
  font-family: 'Ubuntu Mono', monospace;
}

.circularScrollbox {
  width: 200px;
  height: 10.6em;
  padding: 0 2em;
  overflow-Y: scroll;
  background: #161616;
  border: 2px solid aqua;
}

.circularScrollbox>ol {
  list-style-type: none;
  padding-left: 0;
}

.left {
  float: left;
  shape-outside: ellipse(50px 85px at 0% calc(100% - 85px));
  width: 100px;
  height: 100%;
  margin-top:0;
}  
 <link href="https://fonts.googleapis.com/css?family=Ubuntu Mono" rel="stylesheet">

<div class='circularScrollbox'>
  <div class="left"></div>
  <ol class='scrollboxList'>
    <li class="vjListItem">Item 01</li>
    <li class="vjListItem">Item 02</li>
    <li class="vjListItem">Item 03</li>
    <li class="vjListItem">Item 04</li>
    <li class="vjListItem">Item 05</li>
    <li class="vjListItem">Item 06</li>
    <li class="vjListItem">Item 07</li>
    <li class="vjListItem">Item 08</li>
    <li class="vjListItem">Item 09</li>
    <li class="vjListItem">Item 10</li>
    <li class="vjListItem">Item 11</li>
    <li class="vjListItem">Item 12</li>
    <li class="vjListItem">Item 13</li>
    <li class="vjListItem">Item 14</li>
    <li class="vjListItem">Item 15</li>
    <li class="vjListItem">Item 16</li>
    <li class="vjListItem">Item 17</li>
    <li class="vjListItem">Item 18</li>
    <li class="vjListItem">Item 19</li>
    <li class="vjListItem">Item 20</li>
    <li class="vjListItem">Item 21</li>
    <li class="vjListItem">Item 22</li>
    <li class="vjListItem">Item 23</li>
    <li class="vjListItem">Item 24</li>
    <li class="vjListItem">Item 25</li>
    <li class="vjListItem">Item 26</li>
    <li class="vjListItem">Item 27</li>
    <li class="vjListItem">Item 28</li>
    <li class="vjListItem">Item 29</li>
    <li class="vjListItem">Item 30</li>
    <li class="vjListItem">Item 31</li>
    <li class="vjListItem">Item 32</li>
    <li class="vjListItem">Item 33</li>
    <li class="vjListItem">Item 34</li>
    <li class="vjListItem">Item 35</li>
    <li class="vjListItem">Item 36</li>
    <li class="vjListItem">Item 37</li>
    <li class="vjListItem">Item 38</li>
    <li class="vjListItem">Item 39</li>
    <li class="vjListItem">Item 40</li>
  </ol>
</div>  

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

1. Отличное и инновационное решение! Я никогда не думал об использовании CSS-фигур таким образом. Однако на самом деле нет необходимости использовать jQuery: можно легко привязать прослушиватель событий прокрутки, используя vanilla JS 🙂

2. @Terry да, я обленился заниматься чистым JS, сейчас выходные:p .. обновлю позже 😉