web-dev-qa-db-ja.com

向きの変更時にWebページを再レンダリングする最良の方法は何ですか?

向きを変更すると、iphoneでレンダリングがひどく滑らかなCSSレイアウトがあります。 (更新すると正常に表示されます)。

私は以下のコードを使用して、向きの変更時にページを更新しますが、これはうまく機能します-それは少し間違っていると感じています。ページ全体をリロードせずにこれを達成する方法はありますか?これはモバイルサイトです。ユーザーにページを2回読み込ませたくありません。

var supportsOrientationChange = "onorientationchange" in window,
    orientationEvent = supportsOrientationChange ? "orientationchange" : "resize";

window.addEventListener(orientationEvent, function() {
    window.location.reload()
}, false);   

編集:

IPhoneでテストするときの2つの主な問題は次のとおりです。

私は100%幅で、右揃えの背景画像を持っています。向きをポートレートからランドスケープに変更すると、ボディの幅はポートレートモードでのレンダリング方法のままになります。ページが広すぎて、画像を2回レンダリングするように見えるため、横から縦に問題が多くなります。

28
theorise

CSSが既にさまざまなサイズのモバイルデバイス画面でうまくレンダリングされていると仮定すると、テンプレートの<head>でビューポートを定義する必要があります。

たとえば、これはページの幅をデバイスの画面幅に設定し、初期ズームを100%に設定します。最初のズームはページの読み込み時に適用されますが、向きが変更されたときは適用されません。

<meta name="viewport" content="width=device-width, initial-scale=1.0">

ビューポートにmaximum-scale = 1.0パラメーターを追加すると、iPad/iPhoneでズームレベルを維持し、向きの変更時にページを再レイアウトするように強制されます。これの欠点は、ズームが無効になることです。ただし、メディアクエリを使用してレイアウトを調整し、現在の向きに適した方法でコンテンツを表示できるという利点があります。ビューポートの詳細については、こちらをご覧ください: Choosing a ViewPort

次にメディアクエリについて説明します。メディアクエリは、CSSファイルの下部に、画面の幅の最小幅から最大幅の順に配置する必要があります。たとえば、 Html5BoilerPlate CSSの例から取られたもの:

@media only screen and (min-width: 480px) {
  /* Style adjustments for viewports 480px and over go here */

}

@media only screen and (min-width: 768px) {
  /* Style adjustments for viewports 768px and over go here */

}

したがって、通常のスタイルはすべてこの上にあり、最初に適用されます。画面が480px以上の場合はスタイルの次のブロックが適用され、画面が768px以上の場合はスタイルの最後のブロックが適用されます。

1.0の固定ズームレベルとメディアクエリを組み合わせることで、javascriptを使用せずに、画面サイズと向きに応じてサイトのサイズを変更できます。ユーザーがズームする必要がないように、サイトが適切に設計されていることを確認する必要があることは明らかです。サイトがモバイル向けに最適化されている場合、これは問題になりません。

注:他の非サファリモバイルブラウザは、ビューポートで最大縮尺を設定せずにページを再レイアウトする場合があります。しかし、この動作は一貫性がなく、ほとんどの開発者は、実装が他のデバイスより悪い場合でもAppleデバイスに対応しているようです。ただし、ズームレベルを1.0に修正しても問題ありません。

24
BenSwayne

2015年の更新

他のすべての答えは間違っているか時代遅れです。機能するものは次のとおりです。

_  window.addEventListener('orientationchange', function () {
    var originalBodyStyle = getComputedStyle(document.body).getPropertyValue('display');
    document.body.style.display='none';
    setTimeout(function () {
      document.body.style.display = originalBodyStyle;
    }, 10);
  });_

コードは orientationchange event をリッスンし、10ミリ秒後に非表示にして表示することでbody要素のリフローを強制します。 _<meta>_タグやメディアクエリに依存しません。

他の回答ではメディアクエリを使用することを提案しましたが、「更新すると正常に表示される」と言ったため、既に使用しています。

一部の other 回答では、location.reload()の使用が推奨されます。これは、画像などを含むページ全体をリロードするため、非常に非効率的です。特にモバイルでは、これを行いたくありません。

さらに他の回答は、_<meta name="viewport" content="width=device-width, initial-scale=1.0">_またはそのバリエーションを追加することを提案しました。 Safari 7以降、これは機能しなくなりました。 デモ です。動作しないことを確認するには、iPadを横向きモードで起動し、ページを読み込んでから回転します。 flexboxをずっと使用しているにもかかわらず、ページが完全な高さに拡大しないことに注意してください。

それを このページ と比較してください。ここでは、本番環境でボディの非表示/表示テクニックを使用しています。

11
Dan Dascalescu

単一のJavaScriptスタックフレームで再ペイントとリフローを引き起こすメソッドを使用しました。ピンチズームなどを維持するためのアクセシビリティの要件であることが多いため、ビューポート固有の回答には熱心ではありません。

$(window).on('orientationchange', function() {
    document.body.style.display='none';
    document.body.offsetHeight; //cause a reflow
    document.body.style.display='block'; //cause a repaint
}); 

または非jquery同等

window.addEventListener('orientationchange', function () {
    document.body.style.display='none';
    document.body.offsetHeight; //cause a reflow
    document.body.style.display='block'; //cause a repaint
});
3
James Westgate

私は同様の問題を抱えていたので、jQueryでこれを修正しました。

私の場合、_<nav>_要素のスタイルは正しく変更されていませんでした。 kidkaos77のコードの修正バージョンを$.get()と組み合わせて使用​​して、ページの特定の部分のみをロードしました。

_$(window).bind("resize",function() {
    //on resize reload only nav & replace
    $.get("index.php" +  ' nav', function(data) {
        $("nav").replaceWith($(data).find("nav"));
    });
});
_

この方法では、ページ全体をリロードする必要はありませんが、どの要素が方向の変更の影響を受けているかを正確に指定する必要があります。

0
Tommy DC