dbanksdesign
dbanksdesign

Reputation: 183

Position:fixed in iOS5 Moves when input is focused

I have a div at the top of my mobile application that is position:fixed so it will stay on the top of the browser (it scrolls away in ios 4 and lower which is fine). When an input is focused and brings up the keyboard, the div moves down to the middle of the page. See screenshots:

http://dbanksdesign.com/ftp/photo_2.PNG

Edit: Here is a simplified test page: http://dbanksdesign.com/test/

<body>
<div class="fixed"><input type="text" /></div>
<div class="content"></div>
</body>

.fixed { position:fixed; top:0; left:0; width:100%; background:#ccc; }
.content { width:100%; height:1000px; background:#efefef; }

Upvotes: 16

Views: 14581

Answers (6)

Phil
Phil

Reputation: 216

Modified version of pablobart's solution but without scrolling to top:

// Absolute position
$('#your-field').bind('focus',function(e) { 
    setTimeout(function(){
        $('section#footer').css('position','absolute');
        $('section#footer').css('top',($(window).scrollTop() + window.innerHeight) - $('section#footer').height());
    }, 100);
});

// Back to fixed position
$('#your-field').bind('focusout',function(e) { 
    $('section#footer').removeAttr('style');
});

The simple CSS: section#footer *{ position:fixed; bottom:0; left:0; height:42px }*

Upvotes: 3

Hunt Burdick
Hunt Burdick

Reputation: 517

Just hide your fixed element on focus and then show it again on focusout. I bet your users don't need to see it when focused. I know this is not a solution but I think it is a better approach. Keep it simple.

Upvotes: 0

Mark Mckelvie
Mark Mckelvie

Reputation: 343

This solution works pretty well for me. All the code does is wait until the user taps on a text field, then changes the element identified by the 'jQuerySelector' parameter from a 'fixed' to 'static' position. When the text field looses focus (the user tapped on something else) the element's position is changed back to 'fixed'.

// toggles the value of 'position' when the text field gains and looses focus
var togglePositionInResponseToInputFocus = function(jQuerySelector)
{
   // find the input element in question
   var element = jQuery(jQuerySelector); 

   // if we have the element
   if (element) {

      // get the current position value 
      var position = element.css('position'); 

      // toggle the values from fixed to static, and vice versa
      if (position == 'fixed') {
          element.css('position', 'static'); 
      } else if (position == 'static') {
          element.css('position', 'fixed'); 
      }
    }
}; 

And the associated event handlers:

var that = this; 

// called when text field gains focus
jQuery(that.textfieldSelector).on
(
    'focusin', 
    function()
    {
        togglePositionInResponseToInputFocus(that.jQuerySelector); 
    }
);

// called when text field looses focus
jQuery(that.textfieldSelector).on
(
   'focusout',
    function()
    {
        togglePositionInResponseToInputFocus(that.jQuerySelector); 
    }
 );

Upvotes: 1

pablobart
pablobart

Reputation: 2661

Using the JohnW recomendation to use absolute instead of fixed I came up with this workaround:

First set up a bind to detect when the input is onFocus, scroll to the top of the page and change the element position to absolute:

$('#textinput').bind('focus',function(e) { 
  $('html,body').animate({
        scrollTop: 0
   });
  $('#textinput-container').css('position','absolute');
  $('#textinput-container').css('top','0px');
});

Note that I'm using the id textinput for the input and textinput-container for the div top bar that is containing the input.

Set up another bind to detect when the input is not on focus anymore to change the position of the div back to fixed

$('#textinput').bind('blur',function(e) { 
   $('#textinput-container').css('position','fixed');
  $('#textinput-container').css('top','0px');
});

I've been using a similar solution for a bar fixed at the bottom of the page, the code posted should be working for a bar fixed at the top but I didn't test it

Upvotes: 6

Cliff Harris
Cliff Harris

Reputation: 754

The reason the buttons are becoming unclickable is because they have actually scrolled invisibly with the content. They are still there, just not at the location they were originally, nor where you see them.

If you can guess how much the button has moved (based on how much the content has moved) you can click on the invisible button and it will function normally. In other words, if the content has scrolled by 50 pixels, click 50 pixels away from the button and it will work.

You can scroll the content manually (even by a tiny amount) and the buttons will again work as expected.

Upvotes: 0

JohnW
JohnW

Reputation: 409

Unfortunately you are probably best off using absolute positioning for your fixed elements when working with IOS. Yes, IOS5 does claim to support fixed positioning, but it all falls down when you have interactive controls within that fixed element.

I had the same problem with the search box on my switchitoff.net site. In IOS5 the fixed header would jump down the page if the search box gained focus while the page was scrolled. I tried various workarounds, and the one I currently have is a <div> which sits over the search box. When this <div> is clicked the following occurs:

  1. The page is scrolled to the top
  2. The fixed header is changed to absolute
  3. The <div> covering the search box is hidden
  4. The search <input> is focused

The above steps are reversed when the search box loses focus. This solution prevents the header jumping down the page when the search box is clicked, but for a simpler site you are probably better using absolute positioning in the first place.

There is another tricky issue with IOS5 and fixed positioning. If you have clickable elements on your fixed area with body elements scrolled behind them, this can break your touch events.

For example, on switchitoff.net the buttons on the fixed header became unclickable when interactive elements were scrolled behind them. touchstart was not even being fired when these buttons where tapped. Luckily onClick still seemed to work, although this is always a last resort for IOS because of the delay.

Finally notice how (in IOS5) you can click on the fixed header and scroll the page. I know this emulates the way you can use the scroll wheel over a fixed header in a normal browser, but surely this paradigm doesn't make sense for a touch-UI?

Hopefully Apple will continue to refine the handling of fixed elements, but in the meantime it's easier to stick with absolute positioning if you have anything interactive in your fixed area. That or go back to IOS4 when things were so much easier!

Upvotes: 9

Related Questions