Skip to content
This repository has been archived by the owner on Oct 8, 2021. It is now read-only.

Header and footer change their position after keyboard popup - iOS #4113

Closed
mletynski opened this issue Apr 19, 2012 · 70 comments
Closed

Header and footer change their position after keyboard popup - iOS #4113

mletynski opened this issue Apr 19, 2012 · 70 comments

Comments

@mletynski
Copy link

When the content of page does not suit whole screen and we need to scroll, we have a problem with header and footer position.

Just open this link from safari ipad simulator:

http://jsfiddle.net/6ghtb/4/show/

Just click on input number 10 (last one which is visible before scrolling) and observe footer. It just jump and leave space between himself and the keyboard ...

When you scroll down and click most upper input, you have the same problem with header.

screenshot:
https://www.evernote.com/shard/s194/sh/c801a939-06a7-47cc-a3b8-70bb03af0ca1/30f7d6eb650566bfe6032f634b0381e5

@tompie
Copy link

tompie commented Apr 19, 2012

We're facing the same issue. Any workarounds etc. available?

Thanks

@mletynski
Copy link
Author

Come on guys, nobody will answer that ? This bug shows that fixed toolbars are breaking the gui.

@agcolom
Copy link
Contributor

agcolom commented Apr 21, 2012

@mletynski Thanks a lot for the jsfiddle. With which version of iOS are you experiencing this problem?

Thanks,

Anne

@mletynski
Copy link
Author

@agcolom for iOS 5 and 5.1

@agcolom
Copy link
Contributor

agcolom commented Apr 21, 2012

@mletynski I cannot reproduce on the iPod Touch iOS 5.0.1 (do you only experience this on the iPad with iOS 5 and 5.1 or do you see this also on the iPhone/iPod Touch? I'll be able to test on the iPad simulator 5.x later this evening. I have also noticed that you don't have
<meta name="viewport" content="width=device-width, initial-scale="1"">
If you add it as in http://jsfiddle.net/agcolom/6ghtb/5/show/ does it make any difference?

@mletynski
Copy link
Author

I didnt try to reproduce it on iphone or ipod. Im reproducing it on iPad with iOS 4/5 and on iPad simulator 5 and 5.1

My real example has:

meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />"

which unfortunetly does not make any difference ;/

@mletynski
Copy link
Author

@agcolom did you reproduce it ? I can also reproduce it on iPhone 5.1 simulator easly. Important thing here is that content need to be scrollable.

@agcolom
Copy link
Contributor

agcolom commented Apr 23, 2012

@mletynski yes, I just managed to reproduce it on the iPad2 iOS5.1. We had a similar issue a while ago, but it got solved, so I need to check how we solved it then.

@agcolom
Copy link
Contributor

agcolom commented Apr 23, 2012

This looks linked/similar to #1087

@mletynski
Copy link
Author

@agcolom thanks for the hint. I checked what was introduced there and "hideDuringFocus" was added. It is what we are looking for. Unfortunetly there is a "bug" there, in line 7305:

"if( screen.width < 500 && $( e.target ).is( o.hideDuringFocus ) &amp;&amp; !$( e.target ).closest( ".ui-header-fixed, .ui-footer-fixed" ).length ){"

It is is applied only for screen.width<500 ... I don't know why here is such condition ... but for our ipad it is 768 ..

Look like easy fix ...

@toddparker
Copy link
Contributor

@mletynski - Did changing that width threshold fix the issue for you? I think we added this logic because we hide toolbars on smartphones to leave more room for input and virtual keyboard. We figured that at tablet sizes (>500px), there would be enough space to comfortably view the toolbars + input + keyboard so it might look ood to have the toolbars hiding and showin focus/blur.

@ghost ghost assigned scottjehl Apr 28, 2012
@mletynski
Copy link
Author

@toddparker - Yes it works for me after increasing this width threshold.

@toddparker
Copy link
Contributor

@mletynski When you do this, don't the toolbars hide on focus? Do yo think that feels odd?

@mletynski
Copy link
Author

@toddparker Yes they are flickering. But i changed this code a little bit (i removed animated part), so the show and hide are invoked immediately and everythink works perfectly for me.

@mletynski
Copy link
Author

@toddparker will it be fixed in in new jquery mobile version ?

@toddparker
Copy link
Contributor

@mletynski Do you have a test page I could review with the suggested changes you made?

@mletynski
Copy link
Author

@toddparker
Sorry for delay, Unfortunetly header and footer are flickering now. Sometimes header is disappearing ... But its still better then footer placement in middle of the page.
Maybe footer should be hidden when keyboard is coming out from the bottom ? Native ios application behave like that ...

@mletynski
Copy link
Author

Ah now i read your previous post, sorry i was lost with multiply of those issues ... If the original code is hiding toolbars for smartphones after changing this threshold it does hide it for ipad very random ... Sometimes they are hidden, but sometimes not. Maybe its again connected somehow with scrolling issue ...

@mletynski
Copy link
Author

@toddparker
Fix for hiding toolbars for smartphones also does not wotk when page scroll's.

@jaspermdegroot
Copy link
Contributor

@mletynski

Regarding the original issue. Do you see any improvement when you look at http://jsbin.com/otepum/100/ which loads latest code?

@mletynski
Copy link
Author

@uGoMobi

No, the problem still exists. Footer jumps to middle of the page.

@Scalee
Copy link

Scalee commented Jul 3, 2012

@uGoMobi

I also still have this issue with 1.1.1-rc.1.

//Edit new work around for my instance:
//Line 7299 1.1.0
.bind("focusin focusout", function (e) {
if (e.type === "focusin" && $(e.target).is("input, textarea"))
$(self.element).addClass("ui-fixed-hidden");
else
$(self.element).removeClass("ui-fixed-hidden");

@ghost ghost assigned jaspermdegroot Jul 4, 2012
@dheerajpatial14
Copy link

I am facing a problem regarding footer jumping to middle of screen when opening keypad on any field.This problem is occured only in Iphone 4.This application is developed using asp.net.Please give any suggestion...

@MongooseSec
Copy link

Still an issue in iOS6 with JQM 1.2.0.

@jostster
Copy link

I have this issue on my iPhone. Would it be possible to add a flag so the footer will hide but the header won't? This will make it easier for users to press the 'Save' button that we place in the header while an element is still selected.

@arschmitz
Copy link
Contributor

This appears to be a bug in mobile safari not the fixed header and footers set up a test case not using jqm at all with exact same results http://jsfiddle.net/arschmitz/rSGPA/16/show it seems like when the keyboard pops the viewport is moved and not scrolled to center the input. the fixed header/footer are still positioned at 0 top / bottom after scroll i put some scales to demonstrate

arschmitz added a commit to arschmitz/jquery-mobile that referenced this issue Oct 22, 2012
… after scroll and repositioning logic. Fixed: jquery-archive#4337 - Fixed header problem after scrolling content on iOS and Android, jquery-archive#4113 - Header and footer change their position after keyboard popup - iOS, jquery-archive#4724 - Moving through form in Mobile Safari with "Next" and "Previous" system controls causes fixed position, tap-toggle false Header to reveal itself
@hadi77makkawi
Copy link

Am having the same issue, and I have tried all the ways to keep the header in it positions when keyboard popup but nothing worked for me. also I have tried some OBJ C code and it worked perfectly it stoped the repositioning in IOS UIWEBVIEW when keyboard popup. But this OBJ C solution did not work with long form in case you have one filed it might help.
For who might use OBJ C approach:
add this code into - (id)init function in mainviewcontoler.m

[[NSNotificationCenter defaultCenter]
 addObserver:self
 selector:@selector(keyboardWillShow:)
 name:UIKeyboardWillShowNotification object:nil];

then add these two function anywhere in mainviewcontoler.m

  • (void)keyboardWillShow:(NSNotification *)aNotification {

    float x = self.webView.scrollView.bounds.origin.x;
    float y = self.webView.scrollView.bounds.origin.y;
    CGPoint originalOffset = CGPointMake(x, y);

    for (double p = 0.0; p < 0.1; p += 0.001) {
    [self setContentOffset:originalOffset withDelay:p];
    }
    }

  • (void)setContentOffset:(CGPoint)originalOffset withDelay:(double)delay {
    double delayInSeconds = delay;
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
    [self.webView.scrollView setContentOffset:originalOffset animated:NO];
    });
    }

@pmccauley
Copy link

Hadi's fix above does make it a bit better - there is quite a flicker when the keyboard goes away though.

@hadi77makkawi
Copy link

Hey guys I have managed to solve the issue I will provide you with the solution after the weekend (:

A brief of what I did .. I get rid of Iscroll plugin I did some code changes on Cordova ViewControler class. Also I have added some Objective C code to stop pushing the uiwebview when keyboard opens and to call a Java script function when keyboard is open. This java script function re adjust the height of the HTML page after keyboard is up.

@hadi77makkawi
Copy link

@jtara @twilly86

I will explain how I have solved this issue.
Am using Cordova 3.1.0, JQM 1.3.2 and fastclick.js (ftlabs-jsv2)

Objective-C:
In CDVViewContoller.m under Cordova package I have commented the following:

1- In (void)viewDidLoad function
// [[NSNotificationCenter defaultCenter] addObserverForName:UIKeyboardWillShowNotification
// object:nil
// queue:[NSOperationQueue mainQueue]
// usingBlock:^(NSNotification* notification) {
// [weakSelf performSelector:@selector(keyboardWillShow:) withObject:notification afterDelay:0];
// }];

2- Comment the whole - (void)keyboardWillShow:(NSNotification*)notif function:

//- (void)keyboardWillShow:(NSNotification*)notif
//{
// if (![@"true" isEqualToString :[self settingForKey:@"KeyboardShrinksView"]]) {
//
// CGRect keyboardFrame = [notif.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
// keyboardFrame = [self.view convertRect:keyboardFrame fromView:nil];
//
// CGRect newFrame = self.view.bounds;
// CGFloat accessoryHeight = gAccessoryBarHeight;
// CGFloat actualKeyboardHeight = (keyboardFrame.size.height - accessoryHeight);
// newFrame.size.height -= actualKeyboardHeight;
//
// NSString * jsCallBack = [NSString stringWithFormat:@"keyboardShow('%.f')",newFrame.size.height];
// [self.webView stringByEvaluatingJavaScriptFromString:jsCallBack];
//
// return;
// }
//
// CGRect keyboardFrame = [notif.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
// keyboardFrame = [self.view convertRect:keyboardFrame fromView:nil];
//
// CGRect newFrame = self.view.bounds;
// CGFloat accessoryHeight = gAccessoryBarHeight;
// CGFloat actualKeyboardHeight = (keyboardFrame.size.height - accessoryHeight);
// newFrame.size.height -= actualKeyboardHeight;
//
//
//
//// NSLog(@" cordova show : %.2f", newFrame.size.height);
//
// self.webView.frame = newFrame;
// self.webView.scrollView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0);
//
// NSString * jsCallBack = [NSString stringWithFormat:@"keyboardShow('%.f')", newFrame.size.height];
// [self.webView stringByEvaluatingJavaScriptFromString:jsCallBack];
//
// BOOL disableScrollingWhenKeyboardShrinksView = [@"true" isEqualToString :[self settingForKey:@"DisableScrollingWhenKeyboardShrinksView"]];
// if (disableScrollingWhenKeyboardShrinksView) {
// self.webView.scrollView.scrollEnabled = NO;
// }
//
//

//}
3- (void)keyboardWillHide:(NSNotification*)notif to be like that

  • (void)keyboardWillHide:(NSNotification*)notif
    {

    if (![@"true" isEqualToString :[self settingForKey:@"KeyboardShrinksView"]]) {
    return;
    }

    BOOL disableScrollingWhenKeyboardShrinksView = [@"true" isEqualToString :[self settingForKey:@"DisableScrollingWhenKeyboardShrinksView"]];
    if (disableScrollingWhenKeyboardShrinksView) {
    self.webView.scrollView.scrollEnabled = YES;
    }

    CGRect keyboardFrame = [notif.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
    keyboardFrame = [self.view convertRect:keyboardFrame fromView:nil];

    CGRect newFrame = self.view.bounds;
    self.webView.scrollView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0);
    self.webView.frame = newFrame;

    [self.webView stringByEvaluatingJavaScriptFromString:@"keyboardHide()"];

}

4- In MainViewController.m

4.1 in function - (id)init add the following at the end:
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification object:nil];

4.2 add the following function in MainViewController.m
-(void)keyboardWillShow:(NSNotification *)aNotification {

NSDictionary* info = [aNotification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
NSString * jsCallBack = [NSString stringWithFormat:@"keyboardShow('%.f')", kbSize.height];
[self.webView stringByEvaluatingJavaScriptFromString:jsCallBack];


float x = self.webView.scrollView.bounds.origin.x;
float y = self.webView.scrollView.bounds.origin.y;
CGPoint originalOffset = CGPointMake(x, y);

for (double p = 0.0; p < 0.1; p += 0.001) {
    [self setContentOffset:originalOffset withDelay:p];
}

self.webView.scrollView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0);

}
4.3 add the following function in MainViewController.m
-(void)setContentOffset:(CGPoint)originalOffset withDelay:(double)delay {
dispatch_after(0, dispatch_get_main_queue(), ^(void){
[self.webView.scrollView setContentOffset:originalOffset animated:NO];

});

}

5 - My config.xml have the following
"fullscreen" value="true"
"webviewbounce" value="false
"DisallowOverscroll" value="true"
"DisableScrollingWhenKeyboardShrinksView" value="false"
"KeyboardShrinksView" value="true"

6 - In css I have the following for header, page and content:
.ui-header {
position: fixed !important;
top: 0px !important;
right:0px;
left:0px;
text-align: center;
z-index: 1000;
width: 100%;
height: 40px !important;
background: #aa2719 !important;
border: none !important;
padding: 0px !important;
font-weight: normal;
opacity: 1 !important;

  }

.ui-page {

    backface-visibility:hidden !important; 
    -webkit-backface-visibility:hidden !important; 
    -moz-backface-visibility:hidden !important;
    -webkit-transform: rotateY(0deg) !important;
    -moz-transform: rotateY(0deg) !important;
    transform: rotateY(0deg) !important;
    -webkit-transform: translateX(0px) !important; 
    -webkit-transform: translateZ(0px) !important; 
    -webkit-transform: translate3d(0, 0, 0) !important;
    -webkit-box-orient: vertical;
    -webkit-box-pack: justify;
    overflow: hidden !important;
    border: none !important;
  }

.ui-content {
border: none !important;
margin: 0px !important;
position: absolute !important;
bottom:0px !important;
left: 0px !important;
right:0px !important;
top:40px !important;
padding:25px 15px 0px 15px !important;
z-index: 500 !important;
overflow-y: auto;

     -webkit-overflow-scrolling: touch !important;
    -webkit-transform: rotateY(0deg) !important;
    -moz-transform: rotateY(0deg) !important;
    transform: rotateY(0deg) !important;
    -webkit-transform: translateX(0px) !important; 
    -webkit-transform: translateZ(0px) !important; 
    -webkit-transform: translate3d(0, 0, 0) !important;
    backface-visibility:hidden !important; 
    -webkit-backface-visibility:hidden !important; 
    -moz-backface-visibility:hidden !important;

     background: #f1f1f1 !important;
  }

7- JS functions:
var needsFocus_flag=false;
var viewportHeight = document.documentElement.clientHeight;
var global_focus_element=null;

$(document).on('touchstart', 'input, textarea, select', function(e) {

 global_focus_element=$("#"+$(this).attr('id'));
 needsFocus_flag=needsFocus(global_focus_element.prop("tagName").toLowerCase());

});

$(document).on('touchend', 'input, textarea, select', function(e) {

 global_focus_element=$("#"+$(this).attr('id'));
 needsFocus_flag=needsFocus(global_focus_element.prop("tagName").toLowerCase());

});

$(document).on('focus', 'input, textarea, select', function(e) {

global_focus_element=$("#"+$(this).attr('id'));
needsFocus_flag=needsFocus(global_focus_element.prop("tagName").toLowerCase());

});

function needsFocus (type) {

switch (type) {

case 'input':
case 'button':
case 'select':
case 'textarea':
case 'checkbox':
case 'file':
case 'image':
case 'radio':
case 'submit':
  return true;

default:
return false;
}
};

function keyboardShow(keyboardheight){

if (!$('body').hasClass('keyboard_show')) {
      $('body').addClass('keyboard_show');
      $.mobile.silentScroll(0);
      document.body.scrollTop = 0;          
      active_scroll($.mobile.activePage.find('.ui-content'),viewportHeight-keyboardheight);


      setTimeout(function() {
               scroll_to(keyboardheight);
    }, 35);    
}

}
function keyboardHide(){
if ($('.ui-focus').length==0) {
$('body').removeClass('keyboard_show');

       $.mobile.resetActivePageHeight();
       active_scroll($.mobile.activePage.find('.ui-content'),viewportHeight);
 }

}

function active_scroll(el,height){

 $.mobile.resetActivePageHeight(viewportHeight+1);
el.css({ 'overflow-y': 'hidden'});
 setTimeout(function() {
        $.mobile.resetActivePageHeight(height);
         el.css({'overflow-y': 'auto'});
 }, 0);

}

function scroll_to(keyboardheight){

   // In this function am checking if element need to be focused also if there is a need to scroll to which means some time even when keyboard is up the inupt u clicked is already in top (:
 if (needsFocus_flag && (global_focus_element.offset().top+global_focus_element.height()) > (viewportHeight-keyboardheight)) {

     var ui_contentOffset =  $.mobile.activePage.find('.ui-content').offset().top;
     var ui_contentScrolTop =  $.mobile.activePage.find('.ui-content').scrollTop();
     var elementOffset = global_focus_element.offset().top;                 
     var final_value=(elementOffset-ui_contentOffset-65)+ui_contentScrolTop;
      $.mobile.activePage.find('.ui-content').stop().animate({ scrollTop: final_value},600, 'easeOutSine');
  };    

}

8 - in jquery.mobile-1.3.2.js
8.1 search for getScreenHeight and replace its code by the following:
if (this.last_width == null || this.last_height == null || this.last_width != $( window ).width())
{
this.last_height = window.innerHeight || $( window ).height();
this.last_width = $(window).width();
}
return this.last_height;
8.2 comment the following line in jquery.mobile-1.3.2.js
// $.mobile.window.bind( "throttledresize", $.mobile.resetActivePageHeight );

Finally this is it, and sorry for this a lot of code and my bad English ): I hop you guys can get any benefit from it .

Note: that app am doing is Portrait no Landscape I have not test it in Landscape.

@jenshoerburger
Copy link

Same problem here. Drove me crazy. Nothing helped and I cannot change anything in the app.

I solved it with this dirty trick:

$("input, select, textarea").bind("focus",function() {
$("#thefooter").hide()
});
$("input, select, textarea").bind("blur",function() {
$("#thefooter").show()
});

(Of course my footer-DIV has the id="thefooter")

Works like a charm - and the trick is nearly invisible because the footer would be under the keyboard anyhow and isn't accessable for the user.

@neilbaylorrulez
Copy link

Hey There

This will fix all

<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, target-densityDpi=device-dpi" />

they key being "target-densityDpi=device-dpi" - enjoy

@jaspermdegroot
Copy link
Contributor

@neilbaylorrulez - Thanks a lot! We will test that.

@neilbaylorrulez
Copy link

no worries, definitely works in ios7 for my non jQuery mobile project - so i probably shouldnt have been so definitive.

Another viewport meta attribute to play with is: height=device-height
(note that this may throw off some of your other positioning logic)

As an aside, you guys should consider also putting "minimal-ui" into the default meta viewport tag - this will tell ios7 (ios7.1 to be specific, but hopefully other user agents too) to hide the address bar and other browser chrome for a full-screen app

@shanesmith
Copy link

The viewport key suggestions by @neilbaylorrulez don't work for me, unfortunately..

@nuvocode
Copy link

nuvocode commented Sep 3, 2014

Thanks neil! the viewport target density did the trick for me!

@jtara
Copy link

jtara commented Sep 3, 2014

^ Not for long (and not on iOS):

http://www.petelepage.com/blog/2013/02/viewport-target-densitydpi-support-is-being-deprecated/

http://trac.webkit.org/changeset/119527

There don't appear to be many web sites that use target-densitydpi
because it is not supported on iOS. There are also concerns from the
standards community about the design of the feature. It seems our best
course of action is to remove target-densitydpi and address these use
cases via other mechanisms, such as responsive images and device units
in CSS because those approaches are likely to be implemented broadly.

@liangzhenghui
Copy link

啊啊啊啊,it seems that this issue was still not fixed?i face this issue too.悲催~

@dpa99c
Copy link

dpa99c commented May 27, 2015

I encountered this issue in a Cordova app using JQM 1.4.5 with iScroll 5.1.3 testing on iOS 8.3

When the virtual keyboard is shown, scrolling the page using the iScroll widget causes the fixed footer to become unfixed and obscure the content.

The target-densityDpi viewport attribute didn't work for me, so I used a JS solution similar to @jenshoerburger to resolve the issue.

@Chener
Copy link

Chener commented Jun 11, 2015

Put this in the header tag

data-tap-toggle="false" data-hide-during-focus="false"

should do the trick.

@liangzhenghui
Copy link

@Chener thank you very much.yours did the trick for me

@elsewhat
Copy link

Have this problem with a header. Implemented:
<meta name="viewport" content="width=device-width, height=device-height,initial-scale=1.0, maximum-scale=1.0, user-scalable=no,target-densityDpi=device-dpi"/>
and
data-position="fixed" data-tap-toggle="false"

but unfortunately it's still not 100% solved. When I'm in one input field with keyboard active and click in another one, the header usually moves down ~100px

@arschmitz
Copy link
Contributor

@elsewhat that is just how ios works there is not such thing as fixed position with the keyboard is open. any scrolling while the key board is open will cause any fixed position element to scroll with the page.

@elsewhat
Copy link

@arschmitz agree fully that this ought to be fixed in iOS. Instead of solving it at the root, we have to monkey around finding weird workaround

@arschmitz
Copy link
Contributor

@elsewhat there is a workaround you need to force layout anytime there is a scroll which will cause them to update but this is very bad for performance

@lakinmohapatra
Copy link

lakinmohapatra commented Feb 19, 2018

var _originalSize = $(window).width() + $(window).height();
$(window).resize(function(){
if($(window).width() + $(window).height() != _originalSize){
console.log("keyboard show up");
$('#order-checkout-block').hide();
}else{
console.log("keyboard closed");
$('#order-checkout-block').show();
}
});

@jtara
Copy link

jtara commented Feb 19, 2018

lakinmohapatra, did you try that solution on iOS?

Unless something has changed in recent Mobile Safari versions, it does not change the size of window when the keyboard is shown.

But what does it solve? Not the subject of this Issue! Is it meant as a partial solution - e.g. how to determine if the keyboard is shown?

Header and footer change their position after keyboard popup - iOS

Your solution for determining if keyboard shown would work for Android. But this is about iOS.

AFAIK, still, the only way to do that is the way hadi77makkaw showed for Cordova - using native code. I've also used native code in a different hybrid development environment (Rhomobile). I don't know of a way to do it for Mobile Safari itself, as then you can't use native code. So, seems only solvable if using a UIWebView or WKWebView rather than system browser.

@pankajGODB
Copy link

Header and footer change their position after keyboard popup - iOS

  1. Try adding cordova plugin add cordova-plugin-wkwebview-engine plugin for cordova project hope this will help because it helped in my page.
  2. if above plugin doesnot help then remove cordova-plugin-wkwebview-engine and add cordova plugin add cordova-plugin-crosswalk-webview.

Issue will be resolve for header.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.