html
ios
bootstrap-modal
mobile-safari
ios11
kekkeme
fonte
fonte
Respostas:
Corrigi o problema adicionando
position:fixed
ao corpo ao abrir um modal. Espero que isso ajude você.fonte
width:100%
para restringir a largura do corpo à largura do dispositivo. Em alguns casos, dependendo da marcação existente, isso pode ser um problema. Também gosto da solução do @gentleboy (abaixo) para não penalizar outros navegadores sem o problema, pois ao definir o corpo para fixo faz com que o corpo role para cima, o que é um tanto chato.position:fixed
inscrito no corpo da petição. Em vez disso, mudei paraposition:absolute
nohtml
elemento e corrigiu meu problema. Obrigada Jen!Pessoalmente,
position: fixed
role para cima automaticamente . Um tanto irritante !Para evitar penalizar outros dispositivos e versões , aplico esta correção apenas às versões apropriadas do iOS.
** VERSÃO 1 - Correção em todos os modais **
Para o javascript / jQuery
$(document).ready(function() { // Detect ios 11_x_x affected // NEED TO BE UPDATED if new versions are affected var ua = navigator.userAgent, iOS = /iPad|iPhone|iPod/.test(ua), iOS11 = /OS 11_0|OS 11_1|OS 11_2/.test(ua); // ios 11 bug caret position if ( iOS && iOS11 ) { // Add CSS class to body $("body").addClass("iosBugFixCaret"); } });
Para o CSS
/* Apply CSS to iOS affected versions only */ body.iosBugFixCaret.modal-open { position: fixed; width: 100%; }
** VERSÃO 2 - Apenas modais selecionados **
Modifiquei a função para disparar apenas para modais selecionados com uma classe
.inputModal
Apenas os modais com entradas devem ser impactados para evitar a rolagem para o topo.
Para o javascript / jQuery
$(document).ready(function() { // Detect ios 11_x_x affected // NEED TO BE UPDATED if new versions are affected (function iOS_CaretBug() { var ua = navigator.userAgent, scrollTopPosition, iOS = /iPad|iPhone|iPod/.test(ua), iOS11 = /OS 11_0|OS 11_1|OS 11_2/.test(ua); // ios 11 bug caret position if ( iOS && iOS11 ) { $(document.body).on('show.bs.modal', function(e) { if ( $(e.target).hasClass('inputModal') ) { // Get scroll position before moving top scrollTopPosition = $(document).scrollTop(); // Add CSS to body "position: fixed" $("body").addClass("iosBugFixCaret"); } }); $(document.body).on('hide.bs.modal', function(e) { if ( $(e.target).hasClass('inputModal') ) { // Remove CSS to body "position: fixed" $("body").removeClass("iosBugFixCaret"); //Go back to initial position in document $(document).scrollTop(scrollTopPosition); } }); } })(); });
Para o CSS
/* Apply CSS to iOS affected versions only */ body.iosBugFixCaret.modal-open { position: fixed; width: 100%; }
Para o HTML Adicione a classe inputModal ao modal
<div class="modal fade inputModal" tabindex="-1" role="dialog"> ... </div>
Nota bene A função javascript agora é auto-invocada
** ATUALIZAR iOS 11.3 - Bug corrigido 😃🎉 **
No iOS 11.3, o bug foi corrigido. Não há necessidade de testar
OS 11_
emiOS11 = /OS 11_0|OS 11_1|OS 11_2/.test(ua);
Mas tenha cuidado pois o iOS 11.2 ainda é amplamente usado (em abril de 2018). Vejo
stat 1
stat 2
fonte
iOS11 = /OS 11_(\d{1,2})(_{0,1})(\d{1,2})/.test(us);
ios11 = /OS 11_(\d{1,2})/.test(ua);
Esse problema vai além do Bootstrap e não apenas do Safari. É um bug de exibição completa no iOS 11 que ocorre em todos os navegadores. A correção acima não corrige esse problema em todas as instâncias.
O bug é relatado em detalhes aqui:
https://medium.com/@eirik.luka/how-to-fix-the-ios-11-input-element-in-fixed-modals-bug-aaf66c7ba3f8
Supostamente, eles já relataram à Apple como um bug.
fonte
Bug frustrante, obrigado por identificá-lo. Caso contrário, eu estaria batendo meu iphone ou minha cabeça contra a parede.
A correção mais simples é (1 linha de alteração de código):
Basta adicionar o seguinte CSS ao html ou a um arquivo css externo.
<style type="text/css"> .modal-open { position: fixed; } </style>
Aqui está um exemplo completo de trabalho:
.modal-open { position: fixed; }
<link href="https://getbootstrap.com/docs/3.3/dist/css/bootstrap.min.css" rel="stylesheet"> <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#exampleModal" data-whatever="@mdo">Open modal for @mdo</button> <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#exampleModal" data-whatever="@fat">Open modal for @fat</button> <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#exampleModal" data-whatever="@getbootstrap">Open modal for @getbootstrap</button> ...more buttons... <div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> <h4 class="modal-title" id="exampleModalLabel">New message</h4> </div> <div class="modal-body"> <form> <div class="form-group"> <label for="recipient-name" class="control-label">Recipient:</label> <input type="text" class="form-control" id="recipient-name"> </div> <div class="form-group"> <label for="message-text" class="control-label">Message:</label> <textarea class="form-control" id="message-text"></textarea> </div> </form> </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> <button type="button" class="btn btn-primary">Send message</button> </div> </div> </div> </div> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script> <script src="https://getbootstrap.com/docs/3.3/dist/js/bootstrap.min.js"></script>
Enviei um problema aqui: https://github.com/twbs/bootstrap/issues/24059
fonte
Solução mais fácil / limpa:
body.modal-open { position: fixed; width: 100%; }
fonte
Este problema não é mais reproduzível após a atualização de seus dispositivos Apple para iOS 11.3
fonte
Adicione
position: fixed;
abody
quando o modal estiver aberto.$(document).ready(function($){ $("#myBtn").click(function(){ $("#myModal").modal("show"); }); $("#myModal").on('show.bs.modal', function () { $('body').addClass('body-fixed'); }); $("#myModal").on('hide.bs.modal', function () { $('body').removeClass('body-fixed'); }); });
.body-fixed { position: fixed; width: 100%; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script> <link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/> <button type="button" class="btn btn-info btn-lg" id="myBtn">Open Modal</button> <!-- Modal --> <div class="modal fade" id="myModal" role="dialog"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal">×</button> <h4 class="modal-title">Form</h4> </div> <div class="modal-body"> <div class="form-group"> <label class="control-label">Input #1</label> <input type="text" class="form-control"> </div> <div class="form-group"> <label class="control-label">Input #2</label> <input type="text" class="form-control"> </div> <div class="form-group"> <label class="control-label">Input #3</label> <input type="text" class="form-control"> </div> <div class="form-group"> <label class="control-label">Input #4</label> <input type="text" class="form-control"> </div> </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> </div> </div> </div> </div>
fonte
Essas soluções que usam uma
position: fixed
correção de posição com base emscrollTop
funcionam muito bem, mas algumas pessoas (incluindo eu) tiveram outro problema: cursor / cursor do teclado não mostrado quando as entradas estão focadas.Observei que acento circunflexo / cursor funciona apenas quando NÃO usamos
position: fixed
no corpo. Então, depois de tentar várias coisas, eu desisti de usar essa abordagem e decidiu usoposition: relative
embody
e usoscrollTop
para corrigir posição superior do modal vez.Veja o código abaixo:
var iosScrollPosition = 0; function isIOS() { // use any implementation to return true if device is iOS } function initModalFixIOS() { if (isIOS()) { // Bootstrap's fade animation does not work with this approach // iOS users won't benefit from animation but everything else should work jQuery('#myModal').removeClass('fade'); } } function onShowModalFixIOS() { if (isIOS()) { iosScrollPosition = jQuery(window).scrollTop(); jQuery('body').css({ 'position': 'relative', // body is now relative 'top': 0 }); jQuery('#myModal').css({ 'position': 'absolute', // modal is now absolute 'height': '100%', 'top': iosScrollPosition // modal position correction }); jQuery('html, body').css('overflow', 'hidden'); // prevent page scroll } } function onHideModalFixIOS() { // Restore everything if (isIOS()) { jQuery('body').css({ 'position': '', 'top': '' }); jQuery('html, body').scrollTop(iosScrollPosition); jQuery('html, body').css('overflow', ''); } } jQuery(document).ready(function() { initModalFixIOS(); jQuery('#myModal') .on('show.bs.modal', onShowModalFixIOS) .on('hide.bs.modal', onHideModalFixIOS); });
fonte
Como mencionado anteriormente: definir
style.position
property
debody
comofixed
resolve oiOS cursor misplacement
problema.No entanto, esse ganho tem o custo de ser rolado à força para o topo da página.
Felizmente, esse novo
UX
problema pode ser negado sem muita sobrecarga, aproveitandoHTMLElement.style
ewindow.scrollTo()
.A essência básica é neutralizar o
scroll to top
, manipulando o quandobody
do elemento . Isso é feito usando o valor capturado pela variável.style.top
mounting
YOffset
ygap
A partir daí, é simplesmente uma questão de redefinir o
body's
style.top
para0
e reformular a visão do usuário usandowindow.scrollTo(0, ygap)
quandodismounting
.Veja abaixo um exemplo prático.
// Global Variables (Manage Globally In Scope). const body = document.querySelector('body') // Body. let ygap = 0 // Y Offset. // On Mount (Call When Mounting). const onModalMount = () => { // Y Gap. ygap = window.pageYOffset || document.documentElement.scrollTop // Fix Body. body.style.position = 'fixed' // Apply Y Offset To Body Top. body.style.top = `${-ygap}px` } // On Dismount (Call When Dismounting). const onModalDismount = () => { // Unfix Body. body.style.position = 'relative' // Reset Top Offset. body.style.top = '0' // Reset Scroll. window.scrollTo(0, ygap) }
fonte
functions
quandomounting
edismounting
. Obrigado.No caso de alguém estar procurando uma correção para o vanilla js que funciona no IOS> 11.2 e não requer nenhum CSS adicional:
(function() { if (!/(iPhone|iPad|iPod).*(OS 11_[0-2]_[0-5])/.test(navigator.userAgent)) return document.addEventListener('focusin', function(e) { if (!e.target.tagName == 'INPUT' && !e.target.tagName != 'TEXTAREA') return var container = getFixedContainer(e.target) if (!container) return var org_styles = {}; ['position', 'top', 'height'].forEach(function(key) { org_styles[key] = container.style[key] }) toAbsolute(container) e.target.addEventListener('blur', function(v) { restoreStyles(container, org_styles) v.target.removeEventListener(v.type, arguments.callee) }) }) function toAbsolute(modal) { var rect = modal.getBoundingClientRect() modal.style.position = 'absolute' modal.style.top = (document.body.scrollTop + rect.y) + 'px' modal.style.height = (rect.height) + 'px' } function restoreStyles(modal, styles) { for (var key in styles) { modal.style[key] = styles[key] } } function getFixedContainer(elem) { for (; elem && elem !== document; elem = elem.parentNode) { if (window.getComputedStyle(elem).getPropertyValue('position') === 'fixed') return elem } return null } })()
O que isso faz é:
focusin
eventos na páginainput
ou atextarea
e estiver contido em um elemento comfixed
posição, altere a posição do contêiner paraabsolute
enquanto em relaçãoscrollTop
às dimensões originais dos contêineres.fixed
.fonte
Essa solução funcionou para mim e está funcionando bem em todos os navegadores do iOS.
.safari-nav-force{ /* Allows content to fill the viewport and go beyond the bottom */ height: 100%; overflow-y: scroll; /* To smooth any scrolling behavior */ -webkit-overflow-scrolling: touch; }
JavsScript
var iOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream; $('.modal').on('shown.bs.modal', function () { if (iOS && $('.modal').hasClass('in')){ $('html,body').addClass('safari-nav-force'); } }); $('.modal').on('hidden.bs.modal', function () { if (iOS && !$('.modal').hasClass('in')){ $('html,body').removeClass('safari-nav-force'); } });
fonte
Experimente viewport-fit = cover para a meta viewport.
Olhe para isto: https://ayogo.com/blog/ios11-viewport/
fonte
Substitua o css modal e altere-o
position
defixed
paraabsolute
.modal { position: absolute !important; }
fonte
adicionar à posição #modal: absoluto corrige problemas futuros relacionados à posição: corrigido
fonte