iPhoneで向きを変更したときにWebアプリのスケール/ズームをリセットするにはどうすればよいですか?


96

アプリをポートレートモードで起動すると、問題なく動作します。次に、回転して横向きにし、拡大します。横向きモードで正しくスケーリングするには、何かを2回ダブルタップする必要があります。最初にズームイン(通常のダブルタップ動作)し、もう一度ズームアウト(もう一度、通常のダブルタップ動作)します。 。ズームアウトすると、横向きモードの正しい新しいスケールにズームアウトします。

ポートレートに戻すと、より一貫して機能するようです。つまり、方向を縦に戻したときにスケールが正しくなるようにズームを処理します。

これがバグかどうかを確認しようとしていますか?またはこれがJavaScriptで修正できるものであれば?

ビューポートメタコンテンツを使用して、初期スケールを1.0に設定し、最小スケールまたは最大スケールを設定していません(または設定しません)。幅をdevice-widthに設定しています。

何か案は?多くの人が解決策を用意してくれるのはありがたいことだと思います。解決策が根強いからです。


1
完璧なソリューション:JavaScriptなし!stackoverflow.com/a/8727440/805787
Steeven

回答:


89

ジェレミー・キース(@adactio)は、彼のブログオリエンテーションとスケールでこれに対する良い解決策を持っています

マークアップに最大スケールを設定しないことにより、マークアップをスケーラブルに保ちます。

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

次に、このスクリプトでスケーラビリティを再度許可するジェスチャスタートまで、ロード時にJavaScriptでスケーラビリティを無効にします。

if (navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPad/i)) {
    var viewportmeta = document.querySelector('meta[name="viewport"]');
    if (viewportmeta) {
        viewportmeta.content = 'width=device-width, minimum-scale=1.0, maximum-scale=1.0, initial-scale=1.0';
        document.body.addEventListener('gesturestart', function () {
            viewportmeta.content = 'width=device-width, minimum-scale=0.25, maximum-scale=1.6';
        }, false);
    }
}

アップデート22-12-2014:
iPad 1ではこれは機能せず、イベントリスナーで失敗します。次のような.body修正を削除するとわかりました。

document.addEventListener('gesturestart', function() { /* */ });

4
確かに、これはズームを無効にするよりも良いですか?私が見つけた最高の修正:)
danwellman '23

うーん、これはまだズーム機能を無効にします。誰かがこれを行わない簡単な解決策を持っていますか?
Brad Swerdfeger、2012

それは機能しますが、ピンチズームジェスチャーを使用してから画面を回転させると、問題が再び発生することがわかりました。それを修正する方法がわからない。
ニレシュ

3
できます。しかし、ズームするにはユーザーが2回ピンチオープンする必要があることに気づきました。これはmaximum-scale=1.0、ジェスチャーが開始された後もが有効なままであるためだと思います。これを修正する方法はありますか?
LandonSchropp、2012年

3
これは、次の2つの理由で機能しません。1)ジェスチャースタート番号1が無効になるため、ユーザーは2回ジェスチャーする必要があります。2)ユーザーが最初のジェスチャーを2回実行すると壊れるので、ユーザーがまったくジェスチャーを行わない場合にのみ機能します。-誰もが以下のAndrew Ashbacherのソリューションを見てください。それは実際に動作します。
tmsimont

18

Scott Jehlは、加速度計を使用して方向の変化を予測する素晴らしいソリューションを考え出しました。このソリューションは非常に応答が速く、ズームジェスチャを妨げません。

https://github.com/scottjehl/iOS-Orientationchange-Fix

仕組み:この修正は、デバイスの加速度計を聞いて向きの変化がいつ発生するかを予測することで機能します。方向の変更が差し迫っていると見なされると、スクリプトはユーザーのズームを無効にし、ズームを無効にして方向の変更を適切に実行できるようにします。デバイスが縦向きに近づくか、向きが変わった後、スクリプトは再びズームを復元します。このように、ページの使用中にユーザーズームが無効になることはありません。

縮小されたソース:

/*! A fix for the iOS orientationchange zoom bug. Script by @scottjehl, rebound by @wilto.MIT License.*/(function(m){if(!(/iPhone|iPad|iPod/.test(navigator.platform)&&navigator.userAgent.indexOf("AppleWebKit")>-1)){return}var l=m.document;if(!l.querySelector){return}var n=l.querySelector("meta[name=viewport]"),a=n&&n.getAttribute("content"),k=a+",maximum-scale=1",d=a+",maximum-scale=10",g=true,j,i,h,c;if(!n){return}function f(){n.setAttribute("content",d);g=true}function b(){n.setAttribute("content",k);g=false}function e(o){c=o.accelerationIncludingGravity;j=Math.abs(c.x);i=Math.abs(c.y);h=Math.abs(c.z);if(!m.orientation&&(j>7||((h>6&&i<8||h<8&&i>6)&&j>5))){if(g){b()}}else{if(!g){f()}}}m.addEventListener("orientationchange",f,false);m.addEventListener("devicemotion",e,false)})(this);

いいね!エレガントなソリューションのように見えます。
エリザベス

1
これは受け入れられる答えになるはずです!!!! 上記のソリューションで1時間を浪費する前に、これを最初に見たことを願っています:)
tmsimont

1
さらにテストした後、これは信頼性の低いソリューションのようなものです:(それは一貫性がなく、コードを調べた後、理由がわかります...定義された動きの「しきい値」は、特にipadを回転中の角度
tmsimont

回転ロックを使用するすべての人に厄介な結果をもたらす可能性があります...特定の角度で電話を保持し、ズームする機能を失う可能性があります-ユーザーは理由が
わかり

14

同じ問題があり、maximum-scale = 1.0を設定するとうまくいきました。

編集:コメントで述べたように、これはコンテンツが幅解像度を超えている場合を除いてユーザーズームを無効にします。すでに述べたように、これは賢明ではないかもしれません。場合によっては、それが必要になることもあります。

ビューポートコード:

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

素晴らしい解決策。向きを変えても、ページを一定のズームレベル(デバイスの幅に対して)に維持するのに適しています。共有してくれてありがとう!
ルークスティーブンソン

17
欠点は、無効になっているユーザーがサイトにズームインできないことです。
ジェスジェイコブス

これらの方法のすべてが、メディアクエリベースのCSSが新しいデバイスの幅を適切に登録するのを妨げているようだ(例:@media allおよび(max-width:479px)
mheavers

2
ユーザーズームを無効にすることは非常に悪い考えです。以下のAndrew Ashbacherのソリューションを参照してください
tmsimont

iPhoneについてはわかりませんが、iPadでは問題は解決しません。方向の変更時にブラウザがズームインすると、ユーザーが手動でズームアウトできなくなるだけです。
Alejo 2012

3

ビューポートで幅を設定している場合:

<meta name = "viewport" content = "width=device-width; initial-scale=1.0;
 maximum-scale=1.0;" />

次に、ランダムにズームインする方向を変更し(特に画面上でドラッグしている場合)、これを修正して、ここで幅を設定しないでください:

<meta id="viewport" name="viewport" content="initial-scale=1.0; user-scalable=0;
minimum-scale=1.0; maximum-scale=1.0" />

これにより、発生するズームが修正されます。window.onorientationchangeイベントを使用するか、プラットフォームに依存しない(テストに便利)ようにしたい場合は、window.innerWidthメソッドを使用できます。


1

MobileSafariは、オブジェクトのorientationchangeイベントをサポートしwindowます。残念ながら、JavaScriptを介してズームを直接制御する方法はないようです。おそらくmeta、ビューポートを制御するタグを動的に書き込んだり変更したりできるかもしれません。おそらく、このイベントを使用して、CSSを使用してコンテンツのサイズを実際に変更できます。幸運を!


3
ありがとう!はい、メタタグのビューポート値を動的に変更してみましたが、何も起こりませんでした。横向きに回転した場合、ページがSafariウィンドウに収まるように縮尺を維持するために正しくズームしたいようです。これがデフォルトの動作ではないのは私には非常に奇妙に思えます!
エリザベス


1

私は自分のプロジェクトでこの機能を使用しています。

function changeViewPort(key, val) {
    var reg = new RegExp(key, "i"), oldval = document.querySelector('meta[name="viewport"]').content;
    var newval = reg.test(oldval) ? oldval.split(/,\s*/).map(function(v){ return reg.test(v) ? key+"="+val : v; }).join(", ") : oldval+= ", "+key+"="+val ;
    document.querySelector('meta[name="viewport"]').content = newval;
}

だからaddEventListener:

if( /iPad|iPhone|iPod|Android/i.test(navigator.userAgent) ){
    window.addEventListener("orientationchange", function() { 
        changeViewPort("maximum-scale", 1);
        changeViewPort("maximum-scale", 10);
    }
}

0

iOSのネイティブズームを無効にし、代わりにJavaScriptにズーム機能を実装することにより、他の新しい回避策を見つけました。

ズーム/向きの問題に対する他のさまざまな解決策の優れた背景は、SérgioLopesによるものです。向きを縦向きに変更した場合の有名なiOSズームバグの修正

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta name="viewport" id="viewport" content="user-scalable=no,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0" />
    <title>Robocat mobile Safari zoom fix</title>
    <style>
        body {
            padding: 0;
            margin: 0;
        }
        #container {
            -webkit-transform-origin: 0px 0px;
            -webkit-transform: scale3d(1,1,1);
            /* shrink-to-fit needed so can measure width of container http://stackoverflow.com/questions/450903/make-css-div-width-equal-to-contents */
            display: inline-block;
            *display: inline;
            *zoom: 1;
        }
        #zoomfix {
            opacity: 0;
            position: absolute;
            z-index: -1;
            top: 0;
            left: 0;
        }
    </style>
</head>

<body>
    <input id="zoomfix" disabled="1" tabIndex="-1">
    <div id="container">
        <style>
            table {
                counter-reset: row cell;
                background-image: url(http://upload.wikimedia.org/wikipedia/commons/3/38/JPEG_example_JPG_RIP_010.jpg);
            }
            tr {
                counter-increment: row;
            }
            td:before {
                counter-increment: cell;
                color: white;
                font-weight: bold;
                content: "row" counter(row) ".cell" counter(cell);
            }
        </style>
        <table cellspacing="10">
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
        </table>
    </div>

    <script>
    (function() {
        var viewportScale = 1;
        var container = document.getElementById('container');
        var scale, originX, originY, relativeOriginX, relativeOriginY, windowW, windowH, containerW, containerH, resizeTimer, activeElement;
        document.addEventListener('gesturestart', function(event) {
            scale = null;
            originX = event.pageX;
            originY = event.pageY;
            relativeOriginX = (originX - window.pageXOffset) / window.innerWidth;
            relativeOriginY = (originY - window.pageYOffset) / window.innerHeight;
            windowW = window.innerWidth;
            windowH = window.innerHeight;
            containerW = container.offsetWidth;
            containerH = container.offsetHeight;
        });
        document.addEventListener('gesturechange', function(event) {
            event.preventDefault();
            if (originX && originY && event.scale && event.pageX && event.pageY) {
                scale = event.scale;
                var newWindowW = windowW / scale;
                if (newWindowW > containerW) {
                    scale = windowW / containerW;
                }
                var newWindowH = windowH / scale;
                if (newWindowH > containerH) {
                    scale = windowH / containerH;
                }
                if (viewportScale * scale < 0.1) {
                    scale = 0.1/viewportScale;
                }
                if (viewportScale * scale > 10) {
                    scale = 10/viewportScale;
                }
                container.style.WebkitTransformOrigin = originX + 'px ' + originY + 'px';
                container.style.WebkitTransform = 'scale3d(' + scale + ',' + scale + ',1)';
            }
        });
        document.addEventListener('gestureend', function() {
            if (scale && (scale < 0.95 || scale > 1.05)) {
                viewportScale *= scale;
                scale = null;
                container.style.WebkitTransform = '';
                container.style.WebkitTransformOrigin = '';
                document.getElementById('viewport').setAttribute('content', 'user-scalable=no,initial-scale=' + viewportScale + ',minimum-scale=' + viewportScale + ',maximum-scale=' + viewportScale);
                document.body.style.WebkitTransform = 'scale3d(1,1,1)';
                // Without zoomfix focus, after changing orientation and zoom a few times, the iOS viewport scale functionality sometimes locks up (and completely stops working).
                // The reason I thought this hack would work is because showing the keyboard is the only way to affect the viewport sizing, which forces the viewport to resize (even though the keyboard doesn't actually get time to open!).
                // Also discovered another amazing side effect: if you have no meta viewport element, and focus()/blur() in gestureend, zoom is disabled!! Wow!
                var zoomfix = document.getElementById('zoomfix');
                zoomfix.disabled = false;
                zoomfix.focus();
                zoomfix.blur();
                setTimeout(function() {
                    zoomfix.disabled = true;
                    window.scrollTo(originX - relativeOriginX * window.innerWidth, originY - relativeOriginY * window.innerHeight);
                    // This forces a repaint. repaint *intermittently* fails to redraw correctly, and this fixes the problem.
                    document.body.style.WebkitTransform = '';
                }, 0);
            }
        });
    })();
    </script>
</body>
</html>

それは改善されるかもしれませんが、私のニーズのために、私が見た他のすべてのソリューションで発生する主要な欠点を回避します。これまでのところ、iOS4搭載のiPad 2でモバイルSafariを使用してのみテストしました。

focus()/ blur()は、向きを変更して数回ズームした後に発生する可能性があるズーム機能のロックを防ぐための回避策です。

document.body.styleを設定すると、全画面の再描画が強制されます。これにより、ズーム後に再描画が大幅に失敗するという断続的な問題が発生するのを回避できます。


0

エリザベスメタタグに「id」プロパティを追加することで、ビューポートのコンテンツを動的に変更できます。

<meta name="viewport" id="view" content="user-scalable=yes, width=device-width minimum-scale=1, maximum-scale=1" />

それからあなたはただjavascriptで呼び出すことができます:

document.getElementById("view").setAttribute('content','user-scalable=yes, width=device-width, minimum-scale=1, maximum-scale=10');

@bridgestewズームまたはビューポートを動的に変更する場合は、uiwebviewに含まれるサブビュースクロールビューを使用します。他のスレッドにサンプルスニペットを追加しました:リンク
M Penades '17

4
@エリザベスはあなたのために働きますか?横モードに切り替えてもズームはリセットされません。
instanceof me

0

これは別の方法ですが、うまくいくようです。

  1. メタタグを設定してビューポートをscale = 1に制限し、ズームを防止します。

    <meta name = "viewport" content = "width = device-width、initial-scale = 1、minimum-scale = 1、maximum-scale = 1">

  2. JavaScriptを使用して、1/2秒後にメタタグを変更してズームできるようにします。

    setTimeout(function(){document.querySelector( "meta [name = viewport]")。setAttribute( 'content'、 'width = device-width、initial-scale = 1');}、500);

  3. 再びJavaScriptを使用して、向きを変更したら、ページをリロードします。

    window.onorientationchange = function(){window.location.reload();};

デバイスの向きを変えるたびに、最初はズームせずにページがリロードされます。しかし、1/2秒後に、ズーム機能が復元されます。


6
質問されてから5年後に質問に答えることは、何かにつながります。残念ながら、これは2015年のWebの動作とは異なります。ユーザーがデバイスを回転させたときにページをリロードしないでください。
ピエール

0

非常に簡単に実装できる修正を見つけました。フォームの完了時に、フォントサイズが50pxのテキスト要素にフォーカスを設定します。テキスト要素が非表示の場合は機能しないようですが、この要素を非表示にするには、要素の色プロパティを不透明に設定しないと簡単にできません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.