67

Fixed position breaks on header when I click on the "Search Form" text box field. It simply detaches from the top of the page (as it's fixed up there) and starts floating middle of the page when the virtual keyboard opens up.

Normal:

enter image description here

Broken:

enter image description here

Adrian P
  • 6,479
  • 4
  • 38
  • 55
coldblooded01
  • 712
  • 1
  • 6
  • 9
  • I have no idea what you are trying to ask here. Is this a programming question of some sort or are you asking about how to use mobile Safari? Perhaps a screen shot would help. – rmaddy Jan 24 '13 at 02:04
  • Hi, apologies - I wasn't as clear with my description. Have a look at these screenshots taken on the iPad. Normal: http://img6.imageshack.us/img6/7057/photo1cf.png || Abmormal (broken): http://img844.imageshack.us/img844/4678/photoiw.png – coldblooded01 Jan 24 '13 at 02:26
  • 1
    Is this your website? Are you asking, as a developer, how to fix the website so it works properly on the iPad? Or are you just a user of this website trying to figure out what is going on? – rmaddy Jan 24 '13 at 02:34
  • 1
    I'm a developer seeking for advice on how to fix this iOS issue (as I believe anyway). – coldblooded01 Jan 24 '13 at 19:33
  • See the answers on http://stackoverflow.com/questions/7970389/ios-5-fixed-positioning-and-virtual-keyboard – Kevin C. Sep 07 '13 at 20:20
  • Any solution that is not as hacky as the ones below? The "bug" still seems to be remaining - iOS 9.1 – LordTribual Nov 26 '15 at 15:04
  • Possible duplicate of several SO questions. See https://gist.github.com/avesus/957889b4941239490c6c441adbe32398#gistcomment-2193547 for details. – Brian Cannard Sep 04 '17 at 23:34

7 Answers7

17

I really like this solution (http://dansajin.com/2012/12/07/fix-position-fixed/). I packaged it up into a little jQuery plugin so I could:

  • Set which parent gets the class
  • Set which elements this applies to (don't forget "textarea" and "select").
  • Set what the parent class name is
  • Allow it to be chained
  • Allow it to be used multiple times

Code example:

$.fn.mobileFix = function (options) {
    var $parent = $(this),

    $(document)
    .on('focus', options.inputElements, function(e) {
        $parent.addClass(options.addClass);
    })
    .on('blur', options.inputElements, function(e) {
        $parent.removeClass(options.addClass);

        // Fix for some scenarios where you need to start scrolling
        setTimeout(function() {
            $(document).scrollTop($(document).scrollTop())
        }, 1);
    });

    return this; // Allowing chaining
};

// Only on touch devices
if (Modernizr.touch) {
    $("body").mobileFix({ // Pass parent to apply to
        inputElements: "input,textarea,select", // Pass activation child elements
        addClass: "fixfixed" // Pass class name
    });
}

EDIT: Removed unnecessary element

martinedwards
  • 5,577
  • 1
  • 33
  • 35
  • 3
    Good fix, voted up. Unfortunately, this also makes the scroll depth jump to the top, so a long scrolling page with an input in the header (as shown in OP's question) will be a crap experience since you'll lose scroll depth. – typeoneerror Jan 25 '14 at 02:29
  • 3
    Seconding @typeoneerror's note: this does the trick, but unless you keep track of the offset and find a way to prevent scroll, this is problematic for fixed position navigation bars on long-scrolling items. (It's a good solution. Just problematic for that common use case.) – Chris Krycho Oct 11 '14 at 14:32
  • 1
    Your code looks buggy. First of all, why do you get a reference for options.fixedElements, to not use it after that? Also, by the same logic, your parent from the plugin must be the $fixedElements, because, from your example, the parent may or may not be the element on which you want to apply the "fixedfix" class, in your case, the class is applied on the body, whereas the needed element may be a header, or a footer, or whatever. – Lucaci Andrei Aug 27 '15 at 10:50
  • @FlorianB true, mine was just a solution, it looks like the live website uses a jQuery so hopefully it's ok. – martinedwards Jun 27 '16 at 09:32
  • Thanks @LucaciAndrei, I removed the fixedElements variable. The parent can be any element you want it to be, I chose the body so the rest can be done in the CSS (see the original article in my post). – martinedwards Jun 27 '16 at 09:33
  • Here is a gist for React users, based on same solution : https://gist.github.com/pandaiolo/7736141374c900cf0d4e044d181f515e (ditched IE8 compatibility...) – Pandaiolo Jun 28 '16 at 11:01
12

In our case this would fix itself as soon as user scrolls. So this is the fix we've been using to simulate a scroll:

$(document).on('blur', 'input, textarea', function () {
    setTimeout(function () {
        window.scrollTo(document.body.scrollLeft, document.body.scrollTop);
    }, 0);
});
basarat
  • 261,912
  • 58
  • 460
  • 511
5

Based on this good analysis of this issue, I've used this in html and body elements in css:

html,body{
    -webkit-overflow-scrolling : touch !important;
    overflow: auto !important;
    height: 100% !important;
}

it's working great for me.

prashanth padala
  • 255
  • 1
  • 3
  • 13
  • I just confirmed that this is working great for `position: fixed; top: 0px`. However, for `bottom: 0px` (fixed to bottom) it wasn't working for iOS 11. I just upgraded to iOS 12 and now it works perfectly. Thanks! – Aidin Aug 01 '19 at 18:53
  • This is not working for me, as window scroll event isn't triggering anymore – Vizz85 Sep 03 '19 at 11:45
  • Not working in iOS 15.5. – thdoan Sep 29 '22 at 19:45
3

Here's a hacky solution using jQuery:

HTML:

<label for="myField">My Field:</label> <input type="text" id="myField" />

<!-- ... other markup here .... -->

<div class="ad_wrapper">my fixed position container</div>

CSS:

.ad_wrapper {
    position: fixed;
    bottom: 0;
    left: 0;
    width: 100%;
    height: 40px;
    background-color: rgba(0,0,0,0.75);
    color: white;
    text-align: center;
}
.unfixed {
    position: relative;
    left: auto;
    bottom: auto;
}

JS:

$(function () {
    adWrapper = $('.ad_wrapper');

    $(document).on('focusin', 'input, textarea', function() {
        adWrapper.addClass('unfixed');
    })
    .on('focusout', 'input, textarea', function () {
        adWrapper.removeClass('unfixed');
    });
});
Silkster
  • 2,190
  • 15
  • 28
3

All of the solutions that I've tried so far failed one scenario for me: the fixed top navbar would disappear as soon as the keyboard is displayed on an iPhone. What if you want the fixed element to stay fixed in the same position even when the keyboard is displayed? Below is a simple solution that allows this, with a bonus of keeping the fixed element stuck to the top as you scroll the page while the keyboard is visible (i.e., with the focus still inside the input field).

// Let's assume the fixed top navbar has id="navbar"
// Cache the fixed element
var $navbar = $('#navbar');

function fixFixedPosition() {
  $navbar.css({
    position: 'absolute',
    top: document.body.scrollTop + 'px'
  });
}
function resetFixedPosition() {
  $navbar.css({
    position: 'fixed',
    top: ''
  });
  $(document).off('scroll', updateScrollTop);
}
function updateScrollTop() {
  $navbar.css('top', document.body.scrollTop + 'px');
}

$('input, textarea, [contenteditable=true]').on({
  focus: function() {
    // NOTE: The delay is required.
    setTimeout(fixFixedPosition, 100);
    // Keep the fixed element absolutely positioned at the top
    // when the keyboard is visible
    $(document).scroll(updateScrollTop);
  },
  blur: resetFixedPosition
});

To see a demo, fork one of the pens below and view in Debug mode on your iPhone:

https://codepen.io/thdoan/pen/JWYQeN

Here's a version using requestAnimationFrame, but it didn't appear to perform any better, so I stuck with the first version since it's simpler:

https://codepen.io/thdoan/pen/VpvJNX

thdoan
  • 18,421
  • 1
  • 62
  • 57
  • 1
    I'm having a search input into the sticky header. `focus` is causing that the page is scroll to the Top of the page. Your solution is not working for me. I'm trying to fix it. Any idea or tips what can be wrong? – Kosmonaft May 01 '17 at 01:40
  • @Kosmonaft can you provide a codepen or equivalent? – thdoan May 02 '17 at 02:09
  • Yes I can. Here it's(I don't know why on codepen the sticky header is not sticky on iPAD. On my local project is sticky) : https://codepen.io/kosmonaft/pen/bWWaMj – Kosmonaft May 02 '17 at 04:26
  • @Kosmonaft I cannot reproduce on Android, and I can't find someone with an iPad here. Can you try to reproduce the issue on an Android tablet? Regarding header not sticky, try changing to fullpage or debug view. – thdoan May 04 '17 at 10:27
1

What you need to do is set the position of the body to fixed while the user is editing text and then restore it to static when the user is done. You can do this either on focus/blur (shown below), or if a user is opening a modal, you can do it on modal open/close.

$("#myInput").on("focus", function () {
    $("body").css("position", "fixed");
});

$("#myInput").on("blur", function () {
    $("body").css("position", "static");
});
Scott Semyan
  • 187
  • 3
0

Fixed - Did a hack around to push the header back to relative fix position once Search text box was entered. This is a bug in iOS virtual keyboard implementation as it breaks fixed positions on text fields IF page is scrollable. If overflow is hidden / page not scrollable, then it won't break fixed positions when virtual keyboard is executed.

Cheers.

Justus Romijn
  • 15,699
  • 5
  • 51
  • 63
coldblooded01
  • 712
  • 1
  • 6
  • 9