52

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>
Jan Swart
  • 6,761
  • 10
  • 36
  • 45
  • 2
    See this thread for possible solution: http://stackoverflow.com/questions/26845263/ionic-range-cannot-click-on-ios – timmcliu Sep 01 '16 at 21:24
  • I just tested in in Safari on Mac OS X El Capitan and it works, do you still see the problem? http://codepen.io/gboogaart42/pen/NbjqMQ – Gerrit B Nov 22 '16 at 15:57
  • 1
    Refer this thread, it might help you: [http://stackoverflow.com/questions/5484540/recreating-the-html5-range-input-for-mobile-safari-webkit?rq=1](http://stackoverflow.com/questions/5484540/recreating-the-html5-range-input-for-mobile-safari-webkit?rq=1) – Mukesh Rathore May 19 '17 at 18:02
  • Add ```jQuery UI Touch Punch``` this will solve your issue. Here is a CDN link: https://cdnjs.cloudflare.com/ajax/libs/jqueryui-touch-punch/0.2.3/jquery.ui.touch-punch.min.js – Pratik Malvi Oct 15 '19 at 14:14
  • 1
    This worked for me https://github.com/sampotts/rangetouch – rofrol Nov 02 '19 at 07:11

5 Answers5

3

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" />
Cameron Gilbert
  • 884
  • 8
  • 23
2

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.

gmoraleda
  • 1,731
  • 1
  • 17
  • 44
Animan
  • 312
  • 1
  • 10
1

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
    }
);

}

Williwyg
  • 651
  • 5
  • 3
0

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

Yulian
  • 66
  • 6
  • 1
    testing with this page https://www.w3schools.com/howto/howto_js_rangeslider.asp on https://live.browserstack.com iphone 5s , 6 , 8 still have this problem – Exlord Aug 03 '20 at 06:54
-4

Try using jQuery Mobile? 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.