iOS iPad Fixed position breaks when keyboard is opened
SafariMobile SafariSafari Problem Overview
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:
Broken:
Safari Solutions
Solution 1 - Safari
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
Solution 2 - Safari
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);
});
Solution 3 - Safari
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.
Solution 4 - Safari
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');
});
});
Solution 5 - Safari
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, go here on your iPhone:
http://s.codepen.io/thdoan/debug/JWYQeN/gakeYJYOXDPk
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:
Solution 6 - Safari
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");
});
Solution 7 - Safari
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.