27

I have several <input type="number"> elements on my webpage. I'm using jQTouch, and I'm trying to stay fullscreen at all times; that is, horizontal scrolling is bad. Whenever I click an <input> element, the page scrolls right, showing a black border on the right of the screen and de-centering everything. The inputs are offset from the left of the screen, and they begin somewhere toward the middle of the page.

How can I prevent this scrolling on focus?

Stefan Kendall
  • 66,414
  • 68
  • 253
  • 406
  • Possible duplicate of [Disable scrolling when changing focus form elements ipad web app](http://stackoverflow.com/questions/6740253/disable-scrolling-when-changing-focus-form-elements-ipad-web-app) – T J Mar 23 '16 at 07:13
  • 1
    None of the answers on that question nor this question are correct. – Stefan Kendall Mar 24 '16 at 15:02

6 Answers6

18

I just found the solution to this problem in this post Stop page scrolling from focus

Just add onFocus="window.scrollTo(0, 0);" to your input field and you're done! (Tried it with <textarea> and <input type="text" /> on the iPad, but I'm pretty sure it'll work on the iPhone too.)

I was afraid the scrolling would be visible as a flicker or something, but fortunately that is not the case!

Community
  • 1
  • 1
Mischa Magyar
  • 327
  • 3
  • 5
  • perfect solution - tested on iPod5 iOS7! – Vestalis May 15 '14 at 20:10
  • 9
    This seems like it should work, but it's not working for me on an iPhone 5S with iOS 8 in Safari. `event.preventDefault()` in combination with your solution seems like it would definitely work, but I still get the default scrolling behavior. – Benny Schmidt Mar 17 '15 at 17:53
  • does not work on iPhone5 iOS10 cordova 7.1.0 check cacheflowes answer. – David Schumann Jan 17 '18 at 12:01
  • Why would you want to scroll the user to the top of the page if the input is further down the page? That seems worse than any condition the original issue might land you in. – Brandon Durham Nov 16 '22 at 21:56
7

here is how I solved this on the iPhone (mobile Safari) (I used jQuery)

1) create a global variable that holds the current scroll position, and which is updated every time the user scrolls the viewport

var currentScrollPosition = 0;
$(document).scroll(function(){
    currentScrollPosition = $(this).scrollTop();
});

2) bind the focus event to the input field in question. when focused, have the document scroll to the current position

$(".input_selector").focus(function(){
    $(document).scrollTop(currentScrollPosition);
});

Ta Da! No annoying "scroll on focus"

One thing to keep in mind...make sure that the input field is ABOVE the keypad, else you will hide the field. That can be easily mitigated by adding an if-clause.

Maurice
  • 1,223
  • 14
  • 21
3

I would recommend using the jQuery.animate() method linked to above, not just the window.scrollTo(0,0), since iOS animates the page offset properties when an input element is focused. Calling window.scrollTo() just once may not work with the timing of this native animation.

For more background, iOS is animating the pageXOffset and pageYOffset properties of window. You can make a conditional check on these properties to respond if the window has shifted:

if(window.pageXOffset != 0 || window.pageYOffset != 0) {
  // handle window offset here
}

So, to expand on the aforementioned link, this would be a more complete example:

$('input,select').bind('focus',function(e) { 
  $('html, body').animate({scrollTop:0,scrollLeft:0}, 'slow'); 
});
Community
  • 1
  • 1
cacheflowe
  • 759
  • 9
  • 9
  • confirm, setting the scrollTop did not work, animating it with a minimum time of 1 msec did. animating it with 0 msecs didnt - probably it needs to be added to an event queue or something – commonpike Apr 06 '13 at 18:40
  • any solution to the jumpy behavior? It looks terrible when the page scrolls up and then flips down again. preventDefault() does not help – David Schumann Jan 17 '18 at 12:00
0

If the focus is being set programmatically, this is what I would do:

Save the window's scollTop value before changing the focus. Then restore the scrollTop to the saved value immediately after setting focus.

If using jQuery:

var savedScrollTop = $(document).scrollTop(); // save scroll position
<code that changes focus goes here>
$(document).scrollTop(savedScrollTop ); // restore it
Himanshu P
  • 9,586
  • 6
  • 37
  • 46
0

~2023 solution~

To prevent autoscroll, use translateY to briefly position the input element in the center of the screen, tricking the browser into thinking it doesn't need to scroll. Then immediately reset the position on focus.

This hinges on a rather strange event behavior: you can only fake the element position on mousedown, not touchstart or touchend. For some reason, touchstart and touchend have the wrong timing. mousedown does fire on touch in mobile Safari.

Tested in iOS 16.5.1.

// To handle phone orientation change, update these to be dynamic.
// innerHeight - visualViewport.height gives the virtual keyboard height,
// but only when the keyboard is open.
const windowHeight = window.innerHeight;
const virtualKeyboardHeight = window.innerHeight / 2.85;

const preventAutoscroll = (el) => {
  // abort if input is already focused
  if (el === document.activeElement) return;

  // vertically position to the exact center of the screen
  // horizontally position off screen to avoid visual artifact
  const { height, y } = el.getBoundingClientRect();
  const yOffset = (windowHeight - virtualKeyboardHeight) / 2 - height / 2 - y;
  el.style.transform = `translate(-9999px, ${yOffset}px)`;
};

const preventAutoscrollCleanup = (el) => {
  el.style.transform = "";
};

// apply to all elements with the .prevent-autofocus class
[...document.getElementsByClassName("prevent-autofocus")].forEach((input) => {
  // neither touchstart nor touchend work (!)
  // mousedown fires in mobile safari before the autoscroll calculation
  input.addEventListener("mousedown", (e) => preventAutoscroll(e.target));
  input.addEventListener("focus", (e) => preventAutoscrollCleanup(e.target));
});

Raine Revere
  • 30,985
  • 5
  • 40
  • 52
  • For simplicity, I have hardcoded the window height and virtual keyboard height. In reality, these will vary depending on the device and its orientation. When they are off, there will be a small, proportional autoscroll. It *is* possible to completely prevent scrolling if you get the exact center y position. This requires first estimating the virtual keyboard height, then measuring and caching `window.innerHeight - visualViewport.height` in `visualViewport.on('resize', ...)`. See: https://github.com/cybersemics/em/blob/95bc8aaa859a3a32a2d74a63ae271a13af641b88/src/stores/viewport.ts#L19-L45 – Raine Revere Jul 20 '23 at 15:25
-4

Try this, i think the problem is the zoom:

<meta name="viewport" content="width=device-width;initial-scale=1.0; maximum-scale=1.0; user-scalable=0;" />