Disable scrolling when changing focus form elements ipad web app
Asked Answered
V

12

32

I have a web app. I'm trying to disable/prevent the scrolling that occurs when you focus on different form inputs (i.e. the scrolling that occurs as you advance through input elements in a form).

I've already disabled scrolling with this:

 <script type="text/javascript">
     $(document).ready(function() {
         document.ontouchmove = function(e){
              e.preventDefault();
              }
     });
 </script>

To add a little more info - I have a few "slides" that my page consists of. Each are 768x1024 and they are "stacked" on the page (i.e. the page is 768x3072 [1024*3=3072]) and when you click a link I'm using scrollTo jquery plugin to scroll to the next "slide" and .focus() on an input element.

Does anyone know how to do this?

Voyles answered 18/7, 2011 at 22:38 Comment(2)
Please consider my solution. It should be the best approach to solve this, just hook 'focusin'Olive
2023 solution here: https://mcmap.net/q/146038/-preventing-an-lt-input-gt-element-from-scrolling-the-screen-on-iphoneJuliannajulianne
H
14

I've found that in UIWebView, document.body is also sometimes moved. So I use:

    input.onfocus = function () {
        window.scrollTo(0, 0);
        document.body.scrollTop = 0;
    }
Halmstad answered 15/2, 2012 at 18:16 Comment(3)
Does not stop the scrolling, but scrolls to 0,0. This might not be desired.Stubbs
Not a good solution, if the iframe contains multiple inputs we don't want the user to scroll up for each element focused.Evaporite
you would add this after the focus() right? or before?Hydrophilous
O
11

Ooops, the window.scrollTo suggested is kinda lousy and make things unpredictable.

Try this better solution:

jQuery('body').bind('focusin focus', function(e){
  e.preventDefault();
})

Or, just hook your input:

jQuery('input.your-input-class').bind('focusin focus', function(e){
  e.preventDefault();
})

Why? Browsers may scroll the focused form element into view by default on 'focusin' event fired (Firefox has a bug, so hook on focus instead). So, just tell them don't do that explicitly.

BTW, if the focus event is triggered by element.focus() in your code, then even the upon solution would not be functional.

So, a solution to that would be replace you focus trigger to select, i.e.

element.select()

other than element.focus()

If you don't like the element.select() approach since it will select the text inside the input element, then try to create a Range object of the input element text and collapse it if you will, sorry for no time to try that at this moment.

Olive answered 17/7, 2015 at 9:42 Comment(5)
Glad to hear there's a better solution. I agree that the window.scrollTo misbehaves sometimes.Halmstad
This was not working for me; iOS9 iPhone 6+ is firing the event after the keyboard has already opened and the page has scrolled.Runt
Yup. Confirm doesn't work in iOS 9. Tried focus, focusin, select.Hanus
In my case I needed the scroll still work but just not trigger when I focus via js. I added my solution in case someone else needs it. Works on iOS9 and iOS10 for me too.Stefaniastefanie
focus can't be preventedGer
S
6

To prevent the browser from scrolling to the element you move focus to I use jQuerys one event listener. Right before I move the focus to the element we add the listener to the scroll event and counter scroll. The event listener is than removed by jQuery.

var oldScroll = $(window).scrollTop();

$( window ).one('scroll', function() {
    $(window).scrollTop( oldScroll ); //disable scroll just once
});

$('.js-your-element').focus();

This way seems simple, effective to me and works great in all tests I have done.

Hope it helps someone.

Stefaniastefanie answered 20/9, 2016 at 1:48 Comment(1)
Maintains the scroll position, but the screen jumps distractingly in iOS 16.5.1.Juliannajulianne
S
3

If you do not want the input to be editable the answer from kpozin works fine. But as soon as you remove the readonly attribute onfocus or onclick the input field scrolls in focus again.

What really helps and does not impact focus or ability to enter text is adding onFocus="window.scrollTo(0, 0);" to the input elements.

Of course you have to guarantee that the relevant input is not covered by the onscreen keyboard!

See also this post: Preventing an <input> element from scrolling the screen on iPhone?

Spline answered 24/9, 2011 at 19:52 Comment(0)
B
2

Update on this - I've seen the window.scroll(0,0) solution in a couple of different places but it seemed to just make it worse. I have multiple inline text inputs on my page so when moving focus between them the automatic up and down scrolling in Safari made the page almost unusable, especially in landscape orientation.

After fighting iOS 8 for a week on this I found this stops the scrolling. This works when changing focus from one element to another as you need to attach the onblur event to something:

var moveFocus = function (blurId, focusId) {
    var blurInput = document.getElementById(blurId);
    var focusInput = document.getElementById(focusId);
    if (blurInput && focusInput) {
        blurInput.onblur = function () {
            if (focusInput.setSelectionRange && focusInput.setSelectionRange()) {
                var len = focusInput.value.length;
                focusInput.setSelectionRange(len, len);
            }
            focusInput.focus();
        };
        focusInput.focus();
    };
};
Belletrist answered 9/2, 2015 at 11:10 Comment(0)
G
1

For whatever reason, it appears you can mitigate this by applying a keyframe animation to an autoFocused input container.

function App() {
  const [isSearching, setIsSearching] = useState(false);

  return (
    <FixedContainer>
      {isSearching && (
        <Box>
          <Input autoFocus type="text" placeholder="click me" onBlur={() => setIsSearching(false)} />
        </Box>
      )}
    </FixedContainer>
  )
}

const fadeInKeyframes = keyframes`
  0% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
`;

const Box = styled.div`
  animation-name: ${fadeInKeyframes};
  animation-duration: 0.1s;
  animation-timing-function: ease;
  animation-delay: 0s;
  animation-iteration-count: 1;
  animation-direction: normal;
  animation-fill-mode: forwards;
  animation-play-state: running;
`;

https://stackblitz.com/edit/react-ios-input-scroll

Working example: https://react-ios-input-scroll.stackblitz.io

Grandfather answered 16/3, 2020 at 20:4 Comment(1)
This worked for me when changing the browser selection programmatically, but not when the user taps on the input (which was okay in my case). Simpler CSS: .preventAutoscroll { animation: 0.01s 1 fadeInKeyframes; }Juliannajulianne
C
0

Try this answer by BLSully. Give all your input elements a readonly="readonly" attribute initially. This will prevent Mobile Safari from scrolling to it. Remove the attribute on focus and add it again on blur for each element.

Creosol answered 26/8, 2011 at 19:38 Comment(3)
in iOS8 at least, readonly inputs don't receive focus, so this can't work.Acronym
Furthermore, this is not good for accessibility as you can make people/reading software think those fields are really not editable.Hyson
is working for me, if I give to input on touchstart readOnly = true, and on touchend I set readOnly = false and target.focus({preventScroll: true}) linkGeometrize
S
0

This worked for me (using jQuery). It allows the scroll and then returns you to the proper position when you leave the input.

    var saveScrollLeft;
    $("input, textarea")
        .focus(function () {
            clearTimeout(blurTimeoutId);
            saveScrollLeft = $("body").scrollLeft();
            })
        .blur(function () {
            // The user might be moving from one input to another, so we don't want to quickly scroll on blur.  Wait a second and see if they are off all inputs.
            blurTimeoutId = setTimeout(function () {
                $(window).scrollLeft(saveScrollLeft);
                }, 1000);
        });
Staphylorrhaphy answered 19/5, 2014 at 22:3 Comment(0)
M
0

None of the provided solutions worked for me. Since the form that is grabbing the focus (and scrolling page initial display to said form) is below the fold, I simply added a fade-in to the form.

So I add a class name called fade-in, which corresponding css to display:none

using jQuery I then simply do jQuery(".fade-in").fadeIn(); after document ready, and the issue is gone.

This is obviously not limited to using jQuery. Vanilla js can be used for the fade.

Membranophone answered 6/2, 2017 at 2:47 Comment(0)
U
0

In case you are developing a mobile webapp with cordova, there is a plugin for that:

The plugin that solved the problem for me was the Telerik Keyboard Plugin. It is using the basic UIWebView. Install the plugin

cordova plugin add ionic-plugin-keyboard

And call this command after your app loaded:

cordova.plugins.Keyboard.disableScroll(true);

In case you are using the WKWebView, you can use e.g. this plugin

Ulent answered 30/1, 2018 at 14:54 Comment(0)
G
0

To "focus" without any scroll, you may use select. select by default will select all of the text inside an input. To mimic focus behavior and have the caret at the end of the input you can use:

var myInput = document.getElementById('my-input');
var length = myInput.value.length;  // Or determine the value of length any other way
myInput.select();
myInput.setSelectionRange(length, length);
Gaga answered 13/12, 2018 at 21:40 Comment(0)
E
0

If you use element.focus(), change it to element.focus({ preventScroll: true }).

But I'm not sure if it is working on Safari: https://developer.mozilla.org/en-US/docs/Web/API/HTMLOrForeignElement/focus

Edgeways answered 1/9, 2020 at 9:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.