如何在iPhone上的方向更改时重置Web应用程序的缩放/缩放?


96

当我以纵向模式启动我的应用程序时,它可以正常工作。然后我旋转到风景中,并按比例放大。要使其在横向模式下正确缩放,我必须双击两次,首先将其完全放大(正常的双击行为),然后再次将其完全缩小(再次是正常的双击行为) 。缩小时,它会放大到横向模式的正确新比例。

切换回纵向似乎更一致。也就是说,它会处理缩放,以便在方向变回纵向时缩放比例正确。

我想弄清楚这是否是错误?还是这可以用JavaScript修复?

使用视口元内容,我将初始比例设置为1.0,而不是设置最小或最大比例(我也不想要)。我将宽度设置为设备宽度。

有任何想法吗?我知道很多人将不胜感激,因为这似乎是一个长期存在的问题,因此将有一个解决方案。


1
完美的解决方案:无需JavaScript!stackoverflow.com/a/8727440/805787
Steeven,2012年

Answers:


89

Jeremy Keith(@adactio)在他的博客Orientation and scale上对此有很好的解决方案

通过不设置标记的最大比例来保持标记的可伸缩性。

<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);
    }
}


2014年12月12日更新:在iPad 1上无法使用,在事件监听器上失败。我发现删除.body修复程序:

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

4
当然,这比禁用缩放更好吗?我发现的最佳解决方法:)
danwellman 2011年

嗯,这仍然会禁用缩放功能。有人有没有这样做的简单解决方案吗?
Brad Swerdfeger

它有效,但是我观察到如果我使用捏缩放手势然后旋转屏幕,问题会再次出现。不知道如何解决它。
Nilesh 2012年

3
有用。但是,我注意到用户必须捏开两次才能缩放。我猜这是因为maximum-scale=1.0手势开始后仍然有效。有没有什么办法解决这一问题?
LandonSchropp 2012年

3
由于以下两个原因,此方法不起作用:1)禁用手势开始编号1,导致用户需要两次手势。2)它在用户加倍第一个手势后中断,因此它实际上仅在用户根本不做手势时才起作用。-每个人都应在下面查看Andrew Ashbacher的解决方案。真的行。
tmsimont 2012年

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);

真好!看起来像一个优雅的解决方案。
伊丽莎白2012年

1
这应该是公认的答案!!!我希望在浪费一个小时以上的解决方案之前先见识一下:)
tmsimont 2012年

1
经过进一步测试后,这是一种不可靠的解决方案:(它是不一致的,并且在查看代码后,我可以看到为什么...总是无法达到定义的运动“阈值”,特别是如果您将ipad握在旋转时有一个角度
tmsimont 2012年

可能对任何人谁使用旋转锁定讨厌的后果......他们可以在一定角度拿着手机,失去变焦能力-用户将不知道为什么
1owk3y

14

我遇到了同样的问题,并且将maximum-scale设置为1.0对我来说很有效。

编辑:如评论中所述,这会禁用用户缩放,除非内容超出宽度分辨率。如上所述,这可能不明智。在某些情况下也可能需要这样做。

视口代码:

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

不错的解决方案。通过方向更改,可以将页面保持在恒定的缩放级别(相对于设备的宽度)。感谢分享!
路加·史蒂文森

17
缺点是残疾用户无法放大您的网站!
杰西·雅各布斯

我注意到所有这些方法似乎都阻止了基于媒体查询的CSS正确注册新设备的宽度(例如:@media all和(最大宽度:479px)
mheavers 2011年

2
终止用户缩放是一个非常糟糕的主意。见下文安德鲁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
谢谢!是的,我尝试动态更改meta标签的视口值,但没有执行任何操作。在我看来,如果您旋转到“风景”,则希望它正确缩放以保持比例,以使页面适合Safari窗口。对我来说,这不是默认行为似乎很奇怪!
伊丽莎白2010年


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

您可以在Elisabeth的metatag中添加“ 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中包含的子视图scrollview。我在其他线程上添加了示例片段:链接
M Penades,2011年

4
@Elisabeth对您有用吗?当我切换为横向模式时,它不会重置缩放。
instanceof我

0

这是另一种方法,它似乎运行良好。

  1. 设置meta标签以将视口限制为scale = 1,这将阻止缩放:

    <meta name =“ viewport” content =“ width = device-width,初始比例= 1,最小比例= 1,最大比例= 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年网络的工作方式。当用户旋转设备时,不要重新加载页面。
皮埃尔·

0

找到了一个非常容易实现的修复程序。完成表单后,将焦点设置为字体大小为50px的文本元素。如果隐藏了text元素,这似乎不起作用,但是可以通过将元素的color属性设置为不透明来轻松隐藏此元素。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.