Стрелка ползунка вниз, чтобы следовать за большим пальцем

#javascript #jquery #html #css #slider

#javascript #jquery #HTML #css #ползунок

Вопрос:

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

Я использую CSS для размещения стрелки, а также для ее анимации.

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

Спасибо за вашу помощь!

 $(function() {
  var slider = document.getElementById("range-slider");
  var output = document.getElementById("range-slider-output");

  output.innerHTML = slider.value;

  slider.oninput = function() {
    output.innerHTML = this.value;
    // resets state of user icon
    $('.fa-user').removeClass("disabled");

    if (output.innerHTML == 1) {
      document.getElementById("range-slider").setAttribute("aria-valuenow", "1");
      $('.range-slider-icons li:nth-of-type(2) span, .range-slider-icons li:nth-of-type(3) span, .range-slider-icons li:nth-of-type(4) span').addClass('disabled');

    } else if (output.innerHTML == 2) {
      document.getElementById("range-slider").setAttribute("aria-valuenow", "2");
      $('.range-slider-icons li:nth-of-type(3) span, .range-slider-icons li:nth-of-type(4) span').addClass('disabled');

    } else if (output.innerHTML == 3) {
      document.getElementById("range-slider").setAttribute("aria-valuenow", "3");
      $('.range-slider-icons li:nth-of-type(4) span').addClass('disabled');

    } else {
      document.getElementById("range-slider").setAttribute("aria-valuenow", "4");
    }

  }


});  
 .range-slider-output {
  position: relative;
  display: inline-block;
  padding: 0.2em 0.75em 0.25em;
  color: #fff;
  text-align: center;
  background: #666;
  border-radius: 3px;
  width: 100%;
  left: calc(50%);
  flex: 0 0 5%;
  align-self: center;
  margin: 0;
  font-size: 28px;
  -webkit-transform: translateX(-50%);
  transform: translateX(-50%);
  top: -92px;
}

.range-slider-output::before {
  position: absolute;
  top: 50%;
  left: 0;
  content: "";
}

.range-slider-lg .range-slider-output::before {
  top: 48px;
  width: 0;
  height: 0;
  border-style: solid;
  border-width: 12px 12px 0 12px;
  border-color: #666 transparent transparent transparent;
  transition: all 0.7s ease-out;
}

.range-slider-wrap {
  min-width: 250px;
}

input[aria-valuenow='1'] .range-slider-output::before {
  left: 1rem;
}

input[aria-valuenow='2'] .range-slider-output::before {
  left: 32.5%;
}

input[aria-valuenow='3'] .range-slider-output::before {
  left: 64%;
}

input[aria-valuenow='4'] .range-slider-output::before {
  left: 94%;
}

input[type='range'] {
  width: 100%;
  cursor: pointer;
  padding-top: 90px;
}

input[type='range'] {
  -webkit-appearance: none;
}

input[type='range']::-webkit-slider-runnable-track {
  width: 100%;
  height: 5px;
  background: #e6e5e5;
  border: 1px solid #999;
  border-radius: 3px;
  -webkit-appearance: none;
  padding: 0 0.5rem;
}

input[type='range']::-moz-range-track {
  width: 100%;
  height: 5px;
  background: #e6e5e5;
  border: 1px solid #999;
  border-radius: 3px;
}

input[type=range]::-webkit-slider-thumb {
  width: 28px;
  height: 28px;
  margin-top: -11px;
  background: #999;
  border: 1px solid #666;
  border-radius: 50%;
  -webkit-appearance: none;
}

input[type='range']::-moz-range-thumb {
  width: 28px;
  height: 28px;
  margin-top: -11px;
  background: #999;
  border: 1px solid #666;
  border-radius: 50%;
}  
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
  <div class="row">
    <div class="col-md-12">

      <div class="form-group">

        <div class="range-slider-wrap range-slider-lg">

          <input class="range-slider ng-valid ng-dirty ng-touched" step="1" type="range" id="range-slider" min="1" max="4" data-tooltip-top="true" aria-valuenow="3" aria-valuemin="1" aria-valuemax="4">

          <output class="range-slider-output num" id="range-slider-output" for="range-slider"></output>

        </div>

      </div>

    </div>
  </div>
</div>  

Ответ №1:

Дело в том, что вырезы не просто позиционируются по процентам, как:

  • first = 0%
  • секунда = 33,3%
  • третий = 66,6%
  • четвертый = 100%

slider-thumb Имеет измерение… 28 пикселей в вашем случае.
И есть промежутки перед первой меткой и последней…
Стрелка также имеет ширину!

Таким образом, вычисление выравнивания может стать запутанным…

Я не нашел ничего близкого к формуле для всех случаев. Но при использовании calc() с «логическим процентом» и смещением в px , он выполняет работу правильно и реагирует. Это всего лишь вопрос пары попыток и неудачного поиска правильного смещения.

Вот единственные строки, которые я изменил из вашего фрагмента:

 input[aria-valuenow='1']   .range-slider-output::before {
   left: 11px;
}
input[aria-valuenow='2']   .range-slider-output::before {
   left: calc(33.3% - 4px);
}
input[aria-valuenow='3']   .range-slider-output::before {
   left: calc(66.6% - 20px);
}
input[aria-valuenow='4']   .range-slider-output::before {
   left: calc(100% - 36px);
}
  

Я также добавил файлы начальной загрузки (которые были в вашей скрипке).

Обновлен Fiddle

Рабочий фрагмент

 $(function() {
  var slider = document.getElementById("range-slider");
  var output = document.getElementById("range-slider-output");

  output.innerHTML = slider.value;

  slider.oninput = function() {
    output.innerHTML = this.value;
    // resets state of user icon
    $('.fa-user').removeClass("disabled");

    if (output.innerHTML == 1) {
      document.getElementById("range-slider").setAttribute("aria-valuenow", "1");
      $('.range-slider-icons li:nth-of-type(2) span, .range-slider-icons li:nth-of-type(3) span, .range-slider-icons li:nth-of-type(4) span').addClass('disabled');

    } else if (output.innerHTML == 2) {
      document.getElementById("range-slider").setAttribute("aria-valuenow", "2");
      $('.range-slider-icons li:nth-of-type(3) span, .range-slider-icons li:nth-of-type(4) span').addClass('disabled');

    } else if (output.innerHTML == 3) {
      document.getElementById("range-slider").setAttribute("aria-valuenow", "3");
      $('.range-slider-icons li:nth-of-type(4) span').addClass('disabled');

    } else {
      document.getElementById("range-slider").setAttribute("aria-valuenow", "4");
    }

  }


});  
 .range-slider-output {
    position: relative;
    display: inline-block;
    padding: 0.2em 0.75em 0.25em;
    color: #fff;
    text-align: center;
    background: #666;
    border-radius: 3px;
    width: 100%;
    left: calc(50%);
    flex: 0 0 5%;
    align-self: center;
    margin: 0;
    font-size: 28px;
    -webkit-transform: translateX(-50%);
    transform: translateX(-50%);
    top: -92px;
}

.range-slider-output::before {
    position: absolute;
    top: 50%;
    left: 0;
    content: "";
}

.range-slider-lg .range-slider-output::before {
  top: 48px;
  width: 0;
  height: 0;
  border-style: solid;
  border-width: 12px 12px 0 12px;
  border-color: #666 transparent transparent transparent;
  transition: all 0.7s ease-out;
}


.range-slider-wrap {
  min-width: 250px;
}


input[aria-valuenow='1']   .range-slider-output::before {
   left: 11px;
}
input[aria-valuenow='2']   .range-slider-output::before {
   left: calc(33.3% - 4px);
}
input[aria-valuenow='3']   .range-slider-output::before {
   left: calc(66.6% - 20px);
}
input[aria-valuenow='4']   .range-slider-output::before {
   left: calc(100% - 36px);
}



input[type='range'] {
  width: 100%;
  cursor: pointer;
  padding-top: 90px;
}
input[type='range'] {
  -webkit-appearance: none;
}
input[type='range']::-webkit-slider-runnable-track {
  width: 100%;
  height: 5px;
  background: #e6e5e5;
  border: 1px solid #999;
  border-radius: 3px;
  -webkit-appearance: none;
  padding: 0 0.5rem;
}

input[type='range']::-moz-range-track {
  width: 100%;
  height: 5px;
  background: #e6e5e5;
  border: 1px solid #999;
  border-radius: 3px;
}

input[type=range]::-webkit-slider-thumb {
    width: 28px;
    height: 28px;
    margin-top: -11px;
    background: #999;
    border: 1px solid #666;
    border-radius: 50%;
    -webkit-appearance: none;
}

input[type='range']::-moz-range-thumb {
  width: 28px;
  height: 28px;
  margin-top: -11px;
  background: #999;
  border: 1px solid #666;
  border-radius: 50%;
}  
 <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>

<div class="container">
  <div class="row">
    <div class="col-md-12">

      <div class="form-group">

        <div class="range-slider-wrap range-slider-lg">

          <input class="range-slider ng-valid ng-dirty ng-touched" step="1" type="range" id="range-slider" min="1" max="4" data-tooltip-top="true" aria-valuenow="3" aria-valuemin="1" aria-valuemax="4">

          <output class="range-slider-output num" id="range-slider-output" for="range-slider"></output>

        </div>

      </div>

    </div>
  </div>
</div>  

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

1. Спасибо, Луис, за обновленный CSS! Я уже пробовал calc раньше, но вместо использования пикселей я использовал em и rem. Ценю помощь!