2012-05-18 26 views
9

私はasp.netのウェブサイトを持っています。私はipadでサポートされるようにビルドしています。入力要素に注目してキーボードがポップアップすると、位置固定ヘッダーdiv(通常はページとともにスクロールする)は、ページがキーボードの移動量に相当する距離だけポップアップし、入力プロセス。キーボードを元に戻すと、divは元の位置にスナップして再び正常に動作します。私はiOS5でテストしていますので、position:fixedをサポートする必要があります。固定位置divがフリーズ(iPad)

これは既知の問題ですか?誰かがこれに遭遇し、前にそれを扱っていますか?私はこれで何かを見つけることができないようです。

答えて

15

iOS5/iOS6/iOS7で固定位置が壊れています。

編集3:この回答のiOS8の終わりに近い作業フィックスへのリンクを参照してください。

A)ページが

又は

Bをズームされキーボード)による入力取得焦点に(アプリ/ iPhone上で示す):

位置:いずれかのときに固定が壊れています。

jsbin.com/icibaz/3でバグを表示するには、リンクを開いてズームしたり、入力フォーカスを与えます。 edit the htmlは自分で編集できます。

バグについての注意事項(a)および(b):

  1. 入力フォーカスを取得したときtop: 0px; left: 0px;を有する固定DIVは(画面の最上部の上または下)間違った位置に表示され、キーボードが表示されます。

  2. 問題は、画面上の入力の自動センタリング(window.pageYOffsetの変更)と関係があるようです。

  3. onScrollイベントでtop:を(例えば0pxと1pxの間で)変更するように強制すると、ピクセルによって固定divが移動することがわかります。それは間違った場所にとどまっています。

  4. 私が以前に使った解決策の1つはhide the fixed div when an input gets focusです - 他の回答を参照してください。

  5. 固定されたdivは、キーボードが開いたときのページの同じ絶対位置に貼られているようです。

  6. したがって、入力にフォーカスがあるときにdivを絶対位置に変更しますか?編集3:このソリューションを使用して、下のコメントを参照してください。または、キーボードが開く前にpageXOffset/pageYOffset値を保存し、onScrollイベントでそれらの値と現在のpageXOffset/pageYOffset値(キーボードが開いたら現在の値)の差を計算し、その差で固定divをオフセットします。

  7. は、ページがズームされている場合、固定位置と別の問題があるように見える - here(コメントで固定のためのAndroidのサポートについても良い情報here)それを試してみてください。

編集1:再現するにはjsbin(jsfiddleではなく)を使用し、jsbin(編集ページではない)の全画面表示を使用します。 jsfiddle(およびjsbinのビューを編集する)は、コードをiframeの内側に配置し、固定された位置合わせとpageYOffsetを妨害するので避けてください。

編集2:iOSの6とiOS 7のモバイルSafariのposition:fixed;はまだ同じ問題を持っている - おそらく彼らは設計によるものです!

編集3:入力がフォーカスを取得したときに、ヘッダーを絶対配置に変更し、ページスクロールイベントfor exampleにヘッダートップを設定します。この解決策:

  • 入力がフォーカスされていない場合(window.onscrollにひどいジッタがある場合)の固定位置を使用します。
  • ピンチズームを許可しないでください(上記のバグ(a)を避けてください)。
  • 絶対位置を使用し、window.pageYOffset一度入力フォーカス(SOヘッダが正しく配置されている)を取得します。
  • 入力にフォーカスがあるときに、スクロール等しいpageYOffsetにstyle.topを設定した場合
  • (ヘッダもiOS8にonscrollイベント遅延にいくらかジッタによるあろう)。 onscrollは、スクロール終了まで解雇されていないため、iOS8でアプリ内のUIWebViewを使用して、または< = iOS7を使用している場合
  • は、入力が集中したときにスクロールすると、ヘッダは、超神経質になります。
  • は、入力フォーカスを失った後(例input.onblurを使用して、おそらく document.body.onfocusを使用するtider)バック固定位置ヘッダに戻ります。
  • ヘッダーが大きすぎると入力が閉塞/覆い隠される可能性があることに注意してください。
  • キーボードが表示されているとき、私は、iOSページ/ビューポートの高さのバグが原因フッターのために仕事を得ることができませんでした。
  • 編集例仕上げスクロール(私はサポートに同じコードを必要とするとき、私のニーズについてhttp://output.jsbin.com/xujofoze/4/quiet
+0

、これはiOSのバグで判明、私はこれを去ることになります今のところ問題はありますが、あなたの提案は有効ですので、私はこの回答に正しいとマークします – jas

+0

jas、それはiOSのバグの問題のURLへのリンクを与えることは可能ですか? – robocat

+0

私はiOS6で修正されたものを見ていませんが、少なくとも1つの追加のバグが追加されています:http://igstudio.blogspot.com/2012/09/positionfixed-in-ios-6.html固定divにハードウェアアクセラレーションによる合成を強制するCSSプロパティを与えると疑われる場合もあります)。 – robocat

0

を使用してhttp://jsbin.com/xujofoze/4/editとビューを使って、私はそれが簡単に、絶対的な位置付けヘッダを使用し、スクロールする前にそれを隠し、それを表示することが判明iOS4とAndroid)。私の目的のために

、私はtouchstartイベントにヘッダを隠し、および(ちらつきを軽減/応答性を改善するために、プラスいくつかのタイマー)touchendまたはscrollイベントに再びそれを示しています。それは点滅しますが、私が見つけることができる最高の妥協です。一つはtouchmoveイベントを(jQueryのがこれを行う)を使用して、スクロールの開始を検出することができますが、私はのでtouchmoveが私のためにも動作しませんでした:

  1. は定期的にiPadがスクロールする前に再描画を行うには失敗した(つまり、スクロールを開始する前にtopが変更されていても、絶対ヘッダーがスタックされたままになります)。

  2. 入力要素がフォーカスを取得したとき、iPadは要素の自動中心化を行いますが、scrollstartイベントは発生しません(入力がclickの場合はtouchmoveがないため)。

    iOS5を上に固定されたヘッダを実装

を固定し、絶対位置のハイブリッドアプローチを使用することによって改善することができる:入力フォーカスを取得するまで

  • はiOS5を用の固定位置を用います。

  • 入力がフォーカス(キーボードが表示されている)になると、iOS4絶対位置コードに変更されます。

  • キーボードが閉じているときは、固定位置に戻ってください。

キーボードが(例えば、キーボード非表示キーを使用して)閉じているときを検出するためのコードdocument要素にDOMFocusOutイベントを登録し、次のコードのようなものを行うことです。ある要素がフォーカスを取得してから別の要素がフォーカスを失うまでに、DOMFocusOutイベントが発生する可能性があるため、タイムアウトが必要です。

function document_DOMFocusOut() { 
    clearTimeout(touchBlurTimer); 
    touchBlurTimer = setTimeout(function() { 
     if (document.activeElement == document.body) { 
      handleKeyboardHide(); 
     } 
    }.bind(this), 400); 
} 

のように私の固定ヘッダコードが何かをされた:jQueryのモバイルがscrollstartとscrollstopイベントをサポート

{ 
    setup: function() { 
     observe(window, 'scroll', this, 'onWinScroll'); 
     observe(document, 'touchstart', this, 'onTouchStart'); 
     observe(document, 'touchend', this, 'onTouchEnd'); 
     if (isMobile) { 
      observe(document, 'DOMFocusOut', this, 'docBlurTouch'); 
     } else if (isIE) { 
     // see http://ajaxian.com/archives/fixing-loss-of-focus-on-ie for code to go into this.docBlurIe() 
      observe(document, 'focusout', this, 'docBlurIe'); 
     } else { 
      observe(isFirefox ? document : window, 'blur', this, 'docBlur'); 
     } 
    }, 

    onWinScroll: function() { 
     clearTimeout(this.scrollTimer); 
     this.scrolling = false; 
     this.rehomeAll(); 
    }, 

    rehomeAll: function() { 
     if ((isIOS5 && this.scrolling) || isIOS4 || isAndroid) { 
      this.useAbsolutePositioning(); 
     } else { 
      this.useFixedPositioning(); 
     } 
    }, 

    // Important side effect that this event registered on document on iOs. Without it event.touches.length is incorrect for any elements in the document using the touchstart event!!! 
    onTouchStart: function(event) { 
     clearTimeout(this.scrollTimer); 
     if (!this.scrolling && event.touches.length == 1) { 
      this.scrolling = true; 
      this.touchStartTime = inputOrOtherKeyboardShowingElement(event.target) ? 0 : (new Date).getTime(); 
      // Needs to be in touchStart so happens before iPad automatic scrolling to input, also not reliable using touchMove (although jQuery touch uses touchMove to unreliably detect scrolling). 
      this.rehomeAll(); 
     } 
    }, 

    onTouchEnd: function(event) { 
     clearTimeout(this.scrollTimer); 
     if (this.scrolling && !event.touches.length) { 
      var touchedDuration = (new Date).getTime() - this.touchStartTime; 
      // Need delay so iPad can scroll to the input before we reshow the header. 
      var showQuick = this.touchStartTime && touchedDuration < 400; 
      this.scrollTimer = setTimeout(function() { 
       if (this.scrolling) { 
        this.scrolling = false; 
        this.rehomeAll(); 
       } 
      }.bind(this), showQuick ? 0 : 400); 
     } 
    }, 

    // ... more code 
} 

var supportTouch = $.support.touch, 
    scrollEvent = "touchmove scroll", 
    touchStartEvent = supportTouch ? "touchstart" : "mousedown", 
    touchStopEvent = supportTouch ? "touchend" : "mouseup", 
    touchMoveEvent = supportTouch ? "touchmove" : "mousemove"; 

function triggerCustomEvent(obj, eventType, event) { 
    var originalType = event.type; 
    event.type = eventType; 
    $.event.handle.call(obj, event); 
    event.type = originalType; 
} 

// also handles scrollstop 
$.event.special.scrollstart = { 

    enabled: true, 

    setup: function() { 

     var thisObject = this, 
      $this = $(thisObject), 
      scrolling, 
      timer; 

     function trigger(event, state) { 
      scrolling = state; 
      triggerCustomEvent(thisObject, scrolling ? "scrollstart" : "scrollstop", event); 
     } 

     // iPhone triggers scroll after a small delay; use touchmove instead 
     $this.bind(scrollEvent, function(event) { 

      if (!$.event.special.scrollstart.enabled) { 
       return; 
      } 

      if (!scrolling) { 
       trigger(event, true); 
      } 

      clearTimeout(timer); 
      timer = setTimeout(function() { 
       trigger(event, false); 
      }, 50); 
     }); 
    } 
};