Input range slider not working on iOS Safari when clicking on track

IosHtmlMobile Safari

Ios Problem Overview


I have a pretty straight-forward range input slider. It works pretty well on all browsers except on iOS Safari.

The main problem I have is when I click on the slider track, it doesn't move the slider. It merely highlights the slider. It works fine when dragging the thumb. Any ideas on how to fix this?

<div class="slider-wrap">
	<div id="subtractBtn"></div>
    <input type="range" class="slider">
 	<div id="addBtn"></div>
</div>

Ios Solutions


Solution 1 - Ios

For those still looking for a javascript only fix like I did. I ended up just making a "polyfill" for this; it relies on the max attribute of the slider and determines the best step to force the input range on iOS. You can thank me later :)

var diagramSlider = document.querySelector(".diagram-bar");

function iosPolyfill(e) {
  var val = (e.pageX - diagramSlider.getBoundingClientRect().left) /
   (diagramSlider.getBoundingClientRect().right - diagramSlider.getBoundingClientRect().left),
  max = diagramSlider.getAttribute("max"),
  segment = 1 / (max - 1),
  segmentArr = [];

  max++;

  for (var i = 0; i < max; i++) {
    segmentArr.push(segment * i);
  }

  var segCopy = segmentArr.slice(),
  ind = segmentArr.sort((a, b) => Math.abs(val - a) - Math.abs(val - b))[0];

  diagramSlider.value = segCopy.indexOf(ind) + 1;
}

if (!!navigator.platform.match(/iPhone|iPod|iPad/)) {
  diagramSlider.addEventListener("touchend", iosPolyfill, {passive: true});
}

<input type="range" max="6" min="1" value="1" name="diagram selector" class="diagram-bar" />

Solution 2 - Ios

Add the CSS property, -webkit-tap-highlight-color: transparent to the CSS of the element or the complete html page. This will remove the troublesome highlight effect on an element when it is tapped on a mobile device.

Solution 3 - Ios

Safari 5.1 + should support type "range" fully - so it's weird it's not working. did you try adding min/max/step values ? what about trying to use only the pure HTML attribute without any classes that might interfere - try pasting this code and run it on a Safari browser

<input type="range" min="0" max="3.14" step="any">

  • it should be working - if it does, it's probably something related to your css, if not try using one of the pure HTML examples here:

https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/range

Solution 4 - Ios

Enhanced version of the solution presented by Cameron Gilbert. This implementation works for sliders with a min value set to a negative number and optional a step size set.

For those not working with typescript I leave it to you to convert to plain javascript.

if (!!navigator.platform.match(/iPhone|iPad|iPod/)) {
mySlider.addEventListener(
    "touchend",
    (touchEvent: TouchEvent) => {
        var element = touchEvent.srcElement as HTMLInputElement;
        if (element.min && element.max && touchEvent.changedTouches && touchEvent.changedTouches.length > 0) {
            const max = Number(element.max);
            const min = Number(element.min);
            let step = 1;
            if (element.step) {
                step = Number(element.step);
            }
            //Calculate the complete range of the slider.
            const range = max - min;

            const boundingClientRect = element.getBoundingClientRect();
            const touch = touchEvent.changedTouches[0];

            //Calculate the slider value
            const sliderValue = (touch.pageX - boundingClientRect.left) / (boundingClientRect.right - boundingClientRect.left) * range + min;

            //Find the closest valid slider value in respect of the step size
            for (let i = min; i < max; i += step) {
                if (i >= sliderValue) {
                    const previousValue = i - step;
                    const previousDifference = sliderValue - previousValue;
                    const currentDifference = i - sliderValue;
                    if (previousDifference > currentDifference) {
                        //The sliderValue is closer to the previous value than the current value.
                        element.value = previousValue.toString();
                    } else {
                        element.value = i.toString();
                    }

                    //Trigger the change event.
                    element.dispatchEvent(new Event("change"));
                    break;
                }
            }
        }
    },
    {
        passive: true
    }
);

}

Solution 5 - Ios

Try using [jQuery Mobile][1]? The workaround is obnoxious, and I'm pretty sure there's no way to use the native interface with standard HTML. It appears from other threads, you could do an elaborate CSS/JS solution.

[1]: http://api.jquerymobile.com/ "jQuery Mobile API"

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJan SwartView Question on Stackoverflow
Solution 1 - IosCameron GilbertView Answer on Stackoverflow
Solution 2 - IosAnimanView Answer on Stackoverflow
Solution 3 - IosYulianView Answer on Stackoverflow
Solution 4 - IosWilliwygView Answer on Stackoverflow
Solution 5 - Iosuser8822074View Answer on Stackoverflow