Safari in ios8 is scrolling screen when fixed elements get focus

前端 未结 12 1103
失恋的感觉
失恋的感觉 2020-12-12 11:24

In IOS8 Safari there is a new bug with position fixed.

If you focus a textarea that is in a fixed panel, safari will scroll you to the bottom of the page.

T

12条回答
  •  死守一世寂寞
    2020-12-12 11:56

    I found a method that works without the need to change to position absolute!

    Full uncommented code

    var scrollPos = $(document).scrollTop();
    $(window).scroll(function(){
        scrollPos = $(document).scrollTop();
    });
    var savedScrollPos = scrollPos;
    
    function is_iOS() {
      var iDevices = [
        'iPad Simulator',
        'iPhone Simulator',
        'iPod Simulator',
        'iPad',
        'iPhone',
        'iPod'
      ];
      while (iDevices.length) {
        if (navigator.platform === iDevices.pop()){ return true; }
      }
      return false;
    }
    
    $('input[type=text]').on('touchstart', function(){
        if (is_iOS()){
            savedScrollPos = scrollPos;
            $('body').css({
                position: 'relative',
                top: -scrollPos
            });
            $('html').css('overflow','hidden');
        }
    })
    .blur(function(){
        if (is_iOS()){
            $('body, html').removeAttr('style');
            $(document).scrollTop(savedScrollPos);
        }
    });
    

    Breaking it down

    First you need to have the fixed input field toward the top of the page in the HTML (it's a fixed element so it should semantically make sense to have it near the top anyway):

    
    
    
    
        
          Untitled
        
    
        
            
    (content)

    Then you need to save the current scroll position into global variables:

    //Always know the current scroll position
    var scrollPos = $(document).scrollTop();
    $(window).scroll(function(){
        scrollPos = $(document).scrollTop();
    });
    
    //need to be able to save current scroll pos while keeping actual scroll pos up to date
    var savedScrollPos = scrollPos;
    

    Then you need a way to detect iOS devices so it doesn't affect things that don't need the fix (function taken from https://stackoverflow.com/a/9039885/1611058)

    //function for testing if it is an iOS device
    function is_iOS() {
      var iDevices = [
        'iPad Simulator',
        'iPhone Simulator',
        'iPod Simulator',
        'iPad',
        'iPhone',
        'iPod'
      ];
    
      while (iDevices.length) {
        if (navigator.platform === iDevices.pop()){ return true; }
      }
    
      return false;
    }
    

    Now that we have everything we need, here is the fix :)

    //when user touches the input
    $('input[type=text]').on('touchstart', function(){
    
        //only fire code if it's an iOS device
        if (is_iOS()){
    
            //set savedScrollPos to the current scroll position
            savedScrollPos = scrollPos;
    
            //shift the body up a number of pixels equal to the current scroll position
            $('body').css({
                position: 'relative',
                top: -scrollPos
            });
    
            //Hide all content outside of the top of the visible area
            //this essentially chops off the body at the position you are scrolled to so the browser can't scroll up any higher
            $('html').css('overflow','hidden');
        }
    })
    
    //when the user is done and removes focus from the input field
    .blur(function(){
    
        //checks if it is an iOS device
        if (is_iOS()){
    
            //Removes the custom styling from the body and html attribute
            $('body, html').removeAttr('style');
    
            //instantly scrolls the page back down to where you were when you clicked on input field
            $(document).scrollTop(savedScrollPos);
        }
    });
    

提交回复
热议问题