development

iOS 5 고정 위치 및 가상 키보드

big-blog 2020. 6. 26. 07:45
반응형

iOS 5 고정 위치 및 가상 키보드


position : fixed를 통해 화면 하단에 div가 고정 된 모바일 웹 사이트가 있습니다. 양식이있는 페이지에 올 때까지 iOS 5 (iPod Touch에서 테스트 중)에서 제대로 작동합니다. 입력 필드를 탭하고 가상 키보드가 나타나면 갑자기 내 div의 고정 위치가 손실됩니다. 키보드가 표시되어 있으면 div가 페이지와 함께 스크롤됩니다. 완료를 클릭하여 키보드를 닫으면 div가 화면 하단의 위치로 되돌아 가고 position : fixed 규칙을 따릅니다.

다른 사람이 이런 종류의 행동을 경험 한 적이 있습니까? 이것이 예상됩니까? 감사.


내 응용 프로그램 에서이 문제가있었습니다. 여기에 내가 어떻게 작업하고 있습니까?

input.on('focus', function(){
    header.css({position:'absolute'});
});
input.on('blur', function(){
    header.css({position:'fixed'});
});

상단으로 스크롤하여 거기에 배치하기 때문에 iOS 사용자는 이상한 일이 발생하지 않습니다. 다른 사용자가이 동작을 수행 할 수 없도록이를 일부 사용자 에이전트 감지로 랩하십시오.


가상 키보드가 뷰포트를 화면 밖으로 밀어 올리는 약간 다른 ipad 문제가있었습니다. 그런 다음 사용자가 가상 ​​키보드를 닫은 후에도 여전히 뷰포트가 화면에 표시되지 않았습니다. 제 경우에는 다음과 같은 일을했습니다.

var el = document.getElementById('someInputElement');
function blurInput() {
    window.scrollTo(0, 0);
}
el.addEventListener('blur', blurInput, false);

이것은 ipad의 문제를 해결하기 위해 사용하는 코드입니다. 기본적으로 오프셋과 스크롤 위치 간의 불일치를 감지하여 '고정'이 올바르게 작동하지 않음을 의미합니다.

$(window).bind('scroll', function () {
    var $nav = $(".navbar")
    var scrollTop = $(window).scrollTop();
    var offsetTop = $nav.offset().top;

    if (Math.abs(scrollTop - offsetTop) > 1) {
        $nav.css('position', 'absolute');
        setTimeout(function(){
            $nav.css('position', 'fixed');
        }, 1);
    }
});

위치 고정 요소는 키보드를 켰을 때 위치를 업데이트하지 않습니다. Safari가 페이지 크기가 조정되었다고 생각하도록 유도함으로써 요소의 위치가 변경됩니다. 완벽하지는 않지만 적어도 'position : absolute'로 전환하고 변경 내용을 추적하는 것에 대해 걱정할 필요가 없습니다.

다음 코드는 사용자가 키보드를 사용하고있을 때 (입력이 집중되어 있기 때문에) 청취하고 흐림이 들릴 때까지 스크롤 이벤트를 수신 한 다음 크기 조정 트릭을 수행합니다. 지금까지 나를 위해 잘 작동하는 것 같습니다.

    var needsScrollUpdate = false;
    $(document).scroll(function(){
        if(needsScrollUpdate) {
            setTimeout(function() {
                $("body").css("height", "+=1").css("height", "-=1");
            }, 0);
        }
    });
    $("input, textarea").live("focus", function(e) {
        needsScrollUpdate = true;
    });

    $("input, textarea").live("blur", function(e) {
        needsScrollUpdate = false;
    });

이 문제를 연구하는 동안 누군가 가이 스레드에서 발생하는 경우를 대비하여. 이 스레드가이 문제에 대한 내 생각을 자극하는 데 도움이된다는 것을 알았습니다.

이것은 최근 프로젝트에서 이것을위한 나의 해결책이었습니다. "targetElem"의 값을 헤더를 나타내는 jQuery 선택기로 변경하면됩니다.

if(navigator.userAgent.match(/iPad/i) != null){

var iOSKeyboardFix = {
      targetElem: $('#fooSelector'),
      init: (function(){
        $("input, textarea").on("focus", function() {
          iOSKeyboardFix.bind();
        });
      })(),

      bind: function(){
            $(document).on('scroll', iOSKeyboardFix.react);  
                 iOSKeyboardFix.react();      
      },

      react: function(){

              var offsetX  = iOSKeyboardFix.targetElem.offset().top;
              var scrollX = $(window).scrollTop();
              var changeX = offsetX - scrollX; 

              iOSKeyboardFix.targetElem.css({'position': 'fixed', 'top' : '-'+changeX+'px'});

              $('input, textarea').on('blur', iOSKeyboardFix.undo);

              $(document).on('touchstart', iOSKeyboardFix.undo);
      },

      undo: function(){

          iOSKeyboardFix.targetElem.removeAttr('style');
          document.activeElement.blur();
          $(document).off('scroll',iOSKeyboardFix.react);
          $(document).off('touchstart', iOSKeyboardFix.undo);
          $('input, textarea').off('blur', iOSKeyboardFix.undo);
      }
};

};

iOS가 스크롤하는 동안 DOM 조작을 중지하기 때문에 수정이 보류되는 데 약간의 지연이 있지만 트릭을 수행합니다 ...


이 버그에 대해 찾은 다른 답변 중 어느 것도 나를 위해 일하지 않았습니다. 페이지를 34px 뒤로 스크롤하여 모바일 사파리가 스크롤하는 양을 간단하게 수정했습니다. jquery로 :

$('.search-form').on('focusin', function(){
    $(window).scrollTop($(window).scrollTop() + 34);
});

이것은 분명히 모든 브라우저에서 적용되지만 iOS에서 중단되는 것을 방지합니다.


이 문제는 정말 성가신 일입니다.

위에서 언급 한 기술 중 일부를 결합하고 이것을 생각해 냈습니다.

$(document).on('focus', 'input, textarea', function() {
    $('.YOUR-FIXED-DIV').css('position', 'static');
});

$(document).on('blur', 'input, textarea', function() {
    setTimeout(function() {
        $('.YOUR-FIXED-DIV').css('position', 'fixed');
        $('body').css('height', '+=1').css('height', '-=1');
    }, 100);
});

두 개의 고정 탐색 표시 줄이 있습니다 (twitter 부트 스트랩을 사용하는 머리글과 바닥 글). 키보드가 작동하면 이상한 반응을 보였고 키보드가 작동하지 않으면 이상한 반응을 보였습니다.

이 시간 지정 / 지연 수정으로 작동합니다. 나는 여전히 결함을 발견하지만 가끔 고객에게 보여주기에 충분할 것 같습니다.

이것이 당신에게 효과가 있는지 알려주세요. 그렇지 않은 경우 다른 것을 찾을 수 있습니다. 감사.


iOS7과 동일한 문제가 발생했습니다. 하단 고정 요소가 내 시야를 제대로 어지럽히 지 않습니다.

이 메타 태그를 HTML에 추가하면 모두 작동하기 시작했습니다.

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

차이를 만든 부분은 다음과 같습니다.

height=device-height

누군가에게 도움이되기를 바랍니다.


나는 Jory Cunningham대답을하고 그것을 개선했다 :

많은 경우에, 미쳐가는 것은 단지 하나의 요소가 아니라 여러 고정 위치 요소 targetElem이므로이 경우 "고정"하려는 모든 고정 요소를 가진 jQuery 객체가되어야합니다. Ho, 스크롤하면 iOS 키보드가 사라지는 것 같습니다 ...

말할 것도 없이이 AFTER 문서 DOM ready이벤트 나 닫기 </body>태그 직전에 사용해야합니다 .

(function(){
    var targetElem = $('.fixedElement'), // or more than one
        $doc       = $(document),
        offsetY, scrollY, changeY;

    if( !targetElem.length || !navigator.userAgent.match(/iPhone|iPad|iPod/i) )
        return;

    $doc.on('focus.iOSKeyboardFix', 'input, textarea, [contenteditable]', bind);

    function bind(){
        $(window).on('scroll.iOSKeyboardFix', react);
        react();
    }

    function react(){
        offsetY = targetElem.offset().top;
        scrollY = $(window).scrollTop();
        changeY = offsetY - scrollY;

        targetElem.css({'top':'-'+ changeY +'px'});

        // Instead of the above, I personally just do:
        // targetElem.css('opacity', 0);

        $doc.on('blur.iOSKeyboardFix', 'input, textarea, [contenteditable]', unbind)
            .on('touchend.iOSKeyboardFix', unbind);
    }

    function unbind(){
        targetElem.removeAttr('style');
        document.activeElement.blur();

        $(window).off('scroll.iOSKeyboardFix');
        $doc.off('touchend.iOSKeyboardFix blur.iOSKeyboardFix');
    }
})();

내 iOS에서만 실행하고 기본 키보드 스크롤 전후에 scollTop을 측정하고 setTimeout을 사용하여 기본 스크롤이 발생하도록 스크롤 오프셋을 올바르게 결정한다는 점을 제외하고 @NealJMD와 비슷한 솔루션이 있습니다.

var $window = $(window);
var initialScroll = $window.scrollTop();
if (navigator.userAgent.match(/iPhone|iPad|iPod/i)) {
  setTimeout(function () {
    $window.scrollTop($window.scrollTop() + (initialScroll - $window.scrollTop()));
  }, 0);
}

이 방법으로 Ipad 기본 레이아웃 내용을 고정 위치로 고정했습니다.

var mainHeight;
var main = $('.main');

// hack to detects the virtual keyboard close action and fix the layout bug of fixed elements not being re-flowed
function mainHeightChanged() {
    $('body').scrollTop(0);
}

window.setInterval(function () {
    if (mainHeight !== main.height())mainHeightChanged();
    mainHeight = main.height();
}, 100);

@ ds111과 비슷한 문제가있었습니다. 키보드로 웹 사이트를 밀었지만 키보드를 닫을 때 아래로 이동하지 않았습니다.

먼저 @ ds111 솔루션을 시도했지만 두 가지 input필드가 있습니다. 물론, 먼저 키보드가 사라지고 흐려짐이 발생합니다 (또는 이와 유사한 것). input포커스가 한 입력에서 다른 입력으로 직접 전환되었을 때 두 번째 는 키보드 아래에있었습니다.

또한 전체 페이지의 크기가 ipad 크기이므로 "점프 업"이 나에게 충분하지 않았습니다. 그래서 나는 스크롤을 부드럽게 만들었습니다.

마지막으로 이벤트 리스너를 모든 입력, 심지어 현재 숨겨져있는 입력에 연결해야했습니다 live.

모두 함께 다음 자바 스크립트 스 니펫을 다음과 같이 설명 할 수 있습니다. 다음과 같은 블러 이벤트 리스너를 현재와 미래에 연결 input하고 textarea(= live) : 유예 기간 (= window.setTimeout(..., 10))을 기다린 다음 animate({scrollTop: 0}, ...)"키보드가없는 경우에만 정상 (= )으로 부드럽게 스크롤합니다. 표시 "(= if($('input:focus, textarea:focus').length == 0)).

$('input, textarea').live('blur', function(event) {
    window.setTimeout(function() {
        if($('input:focus, textarea:focus').length == 0) {
            $("html, body").animate({ scrollTop: 0 }, 400);
        }
    }, 10)
})

유예 기간 (=는 것을주의 10) 너무 짧거나 더 있지만 키보드가 여전히 표시되지 않을 수 있습니다 input또는이 textarea초점을 맞추고 있습니다. 물론 스크롤을 더 빠르게 또는 느리게하려면 기간 (= 400)을 조정할 수 있습니다


입력에서 포커스 및 블러 이벤트를 찾고, 이벤트가 발생할 때 고정 막대의 위치를 ​​선택적으로 변경하기 위해 스크롤하는이 해결 방법을 찾기 위해 실제로 열심히 노력했습니다. 이것은 방탄이며 모든 경우에 적용됩니다 (<>, 스크롤, 완료 버튼으로 탐색). 참고 id = "nav"는 고정 바닥 글 div입니다. 이것을 표준 js 또는 jquery로 쉽게 포팅 할 수 있습니다. 이것은 전동 공구를 사용하는 사람들을위한 dojo입니다. ;-)

define ([ "dojo / ready", "dojo / query",], function (ready, query) {

ready(function(){

    /* This addresses the dreaded "fixed footer floating when focusing inputs and keybard is shown" on iphone 
     * 
     */
    if(navigator.userAgent.match(/iPhone/i)){
        var allInputs = query('input,textarea,select');
        var d = document, navEl = "nav";
        allInputs.on('focus', function(el){
             d.getElementById(navEl).style.position = "static";
        });

        var fixFooter = function(){
            if(d.activeElement.tagName == "BODY"){
                d.getElementById(navEl).style.position = "fixed";
            }
        };
        allInputs.on('blur', fixFooter);
        var b = d.body;
        b.addEventListener("touchend", fixFooter );
    }

});

}); // 끝 정의


이것은 '올바른'것을 얻기 어려운 문제입니다. 입력 요소 포커스에서 바닥 글을 숨기고 흐리게 표시 할 수 있지만 iOS에서는 항상 신뢰할 수있는 것은 아닙니다. 너무 자주 (10 번에 한 번, 내 iPhone 4S에서) 포커스 이벤트가 실행되지 않는 것 같습니다 (또는 경쟁 조건이있을 수 있음). 바닥 글이 숨겨지지 않습니다.

많은 시행 착오 끝에이 흥미로운 해결책을 찾았습니다.

<head>
    ...various JS and CSS imports...
    <script type="text/javascript">
        document.write( '<style>#footer{visibility:hidden}@media(min-height:' + ($( window ).height() - 10) + 'px){#footer{visibility:visible}}</style>' );
    </script>
</head>

기본적으로 : JavaScript를 사용하여 장치의 창 높이를 결정한 다음 창의 높이가 10 픽셀 줄어들 때 바닥 글을 숨기려면 CSS 미디어 쿼리를 동적으로 작성하십시오. 키보드를 열면 브라우저 디스플레이 크기가 조정되므로 iOS에서는 절대 실패하지 않습니다. JavaScript가 아닌 CSS 엔진을 사용하기 때문에 훨씬 빠르고 원활합니다!

참고 : 'display : none'또는 'position : static'보다 'visibility : hidden'을 덜 글리치하게 사용했지만 마일리지가 다를 수 있습니다.


나를 위해 작동

if (navigator.userAgent.match(/iPhone|iPad|iPod/i)) {
    $(document).on('focus', 'input, textarea', function() {
        $('header').css({'position':'static'});
    });
    $(document).on('blur', 'input, textarea', function() {
        $('header').css({'position':'fixed'});
    });
}

우리의 경우 이것은 사용자가 스크롤하자마자 스스로 고쳐질 것입니다. 이것은 우리가에 스크롤을 시뮬레이션하기 위해 사용하고 수정이다 그래서 blur어떤에서 input또는 textarea:

$(document).on('blur', 'input, textarea', function () {
    setTimeout(function () {
        window.scrollTo(document.body.scrollLeft, document.body.scrollTop);
    }, 0);
});

내 대답은 할 수 없다는 것입니다.

25 답변이 있지만 내 경우에는 작동하지 않습니다. 키보드가 켜져있을 때 Yahoo 및 다른 페이지가 고정 헤더를 숨기는 이유입니다. 그리고 Bing은 전체 페이지를 스크롤 할 수 없게합니다 (overflow-y : hidden).

위에서 논의한 사례는 다르며, 일부는 스크롤 할 때 문제가 있고, 일부는 초점 또는 흐림입니다. 일부에는 바닥 글 또는 머리글이 고정되어 있습니다. 이제 각 조합을 테스트 할 수는 없지만 귀하의 경우에는 수행 할 수 없다는 것을 깨닫게 될 수 있습니다.


Github에서이 솔루션을 찾았습니다.

https://github.com/Simbul/baker/issues/504#issuecomment-12821392

스크롤 가능한 내용이 있는지 확인하십시오.

// put in your .js file
$(window).load(function(){
    window.scrollTo(0, 1);
});

// min-height set for scrollable content
<div id="wrap" style="min-height: 480px">
  // website goes here
</div>

검색 주소창은 추가 보너스로 접 힙니다.


누구든지 이것을 시도하고 싶을 때. 입력 필드가있는 고정 바닥 글에서 다음을 수행했습니다.

<script>
    $('document').ready(
        function() {
            if (navigator.userAgent.match(/Android/i) || navigator.userAgent.match(/webOS/i) || navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPad/i)
                  || navigator.userAgent.match(/iPod/i) || navigator.userAgent.match(/BlackBerry/i) || navigator.userAgent.match(/Windows Phone/i)) {
                var windowHeight = $(window).height();
                var documentHeight = $(document).height();

                $('#notes').live('focus', function() {
                    if (documentHeight > windowHeight) {
                        $('#controlsContainer').css({
                            position : 'absolute'
                        });
                        $("html, body").animate({
                            scrollTop : $(document).height()
                        }, 1);
                    }
                });
                $('#notes').live('blur', function() {
                    $('#controlsContainer').css({
                        position : 'fixed'
                    });
                    $("html, body").animate({
                        scrollTop : 0
                    }, 1);
                });
            }
        });
</script>

나는 같은 문제가 있습니다. 그러나 나는 고정 된 위치가 지연되고 깨지지 않았다는 것을 깨달았습니다 (적어도 나를 위해). 5-10 초 정도 기다렸다가 div가 화면 하단으로 다시 조정되는지 확인하십시오. 키보드가 열려있을 때 오류가 아니라 지연된 응답이라고 생각합니다.


이 스레드에서 모든 접근 방식을 시도했지만 도움이되지 않으면 더 악화되었습니다. 결국, 나는 강제로 장치가 초점을 풀도록 결정했습니다.

$(<selector to your input field>).focus(function(){
    var $this = $(this);
    if (<user agent target check>) {
        function removeFocus () {
            $(<selector to some different interactive element>).focus();
            $(window).off('resize', removeFocus);
        }
        $(window).on('resize', removeFocus);
    }
});

그리고 그것은 매력처럼 작동하고 끈적 끈적한 로그인 양식을 수정했습니다.

제발 참고 :

  1. The JS code above is only to present my idea, to execute this snippet please replace values in angular braces (<>) with appropriate values for your situation.
  2. This code is designed to work with jQuery v1.10.2

This is still a large bug for for any HTML pages with taller Bootstrap Modals in iOS 8.3. None of the proposed solutions above worked and after zooming in on any field below the fold of a tall modal, Mobile Safari and/or WkWebView would move the fixed elements to where the HTML body's scroll was situated, leaving them misaligned with where they actually where laid out.

To workaround the bug, add an event listener to any of your modal inputs like:

$(select.modal).blur(function(){
  $('body').scrollTop(0);
});

I'm guessing this works because forcing the HTML body's scroll height re-aligns the actual view with where the iOS 8 WebView expects the fixed modal div's contents to be.


If anybody was looking for a completely different route (like you are not even looking to pin this "footer" div as you scroll but you just want the div to stay at the bottom of the page), you can just set the footer position as relative.

That means that even if the virtual keyboard comes up on your mobile browser, your footer will just stay anchored to the bottom of the page, not trying to react to virtual keyboard show or close.

Obviously it looks better on Safari if position is fixed and the footer follows the page as you scroll up or down but due to this weird bug on Chrome, we ended up switching over to just making the footer relative.


None of the scrolling solutions seemed to work for me. Instead, what worked is to 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. This keeps safari from scrolling your content on you. You can do this either on focus/blur of the element(s) (shown below for a single element but could be for all input, textareas), or if a user is doing something to begin editing like opening a modal, you can do it on that action (e.g. modal open/close).

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

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

iOS9 - same problem.

TLDR - source of the problem. For solution, scroll to bottom

I had a form in a position:fixed iframe with id='subscribe-popup-frame'

As per the original question, on input focus the iframe would go to the top of the document as opposed to the top of the screen.

The same problem did not occur in safari dev mode with user agent set to an idevice. So it seems the problem is caused by iOS virtual keyboard when it pops up.

I got some visibility into what was happening by console logging the iframe's position (e.g. $('#subscribe-popup-frame', window.parent.document).position() ) and from there I could see iOS seemed to be setting the position of the element to {top: -x, left: 0} when the virtual keyboard popped up (i.e. focussed on the input element).

So my solution was to take that pesky -x, reverse the sign and then use jQuery to add that top position back to the iframe. If there is a better solution I would love to hear it but after trying a dozen different approaches it was the only one that worked for me.

Drawback: I needed to set a timeout of 500ms (maybe less would work but I wanted to be safe) to make sure I captured the final x value after iOS had done its mischief with the position of the element. As a result, the experience is very jerky . . . but at least it works

Solution

        var mobileInputReposition = function(){
             //if statement is optional, I wanted to restrict this script to mobile devices where the problem arose
            if(screen.width < 769){
                setTimeout(function(){
                    var parentFrame = $('#subscribe-popup-frame',window.parent.document);
                    var parentFramePosFull = parentFrame.position();
                    var parentFramePosFlip = parentFramePosFull['top'] * -1;
                    parentFrame.css({'position' : 'fixed', 'top' : parentFramePosFlip + 'px'});
                },500);
            }    
        }   

Then just call mobileInputReposition in something like $('your-input-field).focus(function(){}) and $('your-input-field).blur(function(){})

참고URL : https://stackoverflow.com/questions/7970389/ios-5-fixed-positioning-and-virtual-keyboard

반응형