禁用 iOS 10+ Safari 上的视口缩放?

186

我已经将我的iPhone 6 Plus 升级到 iOS 10 beta 版本,发现在移动版 Safari 中,您可以通过双击或缩放的方式缩放任何网页,忽略 meta 标签中的 user-scalable=no 代码。我不知道这是一个错误还是功能。如果它被认为是一个功能,我们如何在iOS 10 Safari中禁用视口缩放?


更新至 iOS 11/12 版本后,iOS 11和iOS 12 Safari仍然不遵守 user-scalable=no meta标签。

Safari上的移动 GitHub 网站


4
一个无障碍功能:值得注意的是,在iOS 10上的Safari浏览器中 http://twitter.com/thomasfuchs/status/742531231007559680/photo/1 - ErikE
107
不是这样的。对于普通网页内容来说,这是一种不好的做法。对于Web应用程序而言,默认的缩放行为可能会完全破坏可用性。例如,没有人想要因为误点两次按键而放大“频道上移”按钮,也没有人想要因为误点跳跃按钮两次而放大视频游戏的某个部分。添加此功能有其原因,因此仅仅因为某些“网站设计师”不知道自己在做什么就让所有用户遭受可用性问题是毫无意义的。去抱怨网站设计师,并停止破坏浏览器。 - dgatwood
64
称这是“不好的做法”是一种观点,但这并不能改变苹果公司坚持采取跨平台实施数月/数年/数十年的网络标准并对其进行大规模破坏的事实。为什么苹果应该决定网页设计师不知道自己在做什么?这是一个很糟糕的论点。 - samrap
2
我个人认为,这源于在线样板代码,开发人员盲目复制粘贴而不知道代码的目的。 - William Isted
11
答案很简单,苹果:将禁用元标记设置为默认关闭的无障碍功能。那些需要它的人将拥有它,而不会惩罚那些不需要它的人。 - Ruben Martinez Jr.
显示剩余4条评论
19个回答

107

在iOS 10的Safari中,可以防止网页缩放,但这将需要更多您的工作。我想争论的是,难度应该阻止盲目开发人员在每个视口标记中添加"user-scalable=no"并使视力受损的用户面临不必要的困难。

尽管如此,我仍希望看到苹果公司改变他们的实现方式,以便有一种简单(元标记)的方法来禁用双击缩放功能。大部分困难与该交互有关。

您可以使用类似以下内容来停止捏合缩放:

document.addEventListener('touchmove', function (event) {
  if (event.scale !== 1) { event.preventDefault(); }
}, false);
注意,如果任何更深层次的目标在事件上调用了stopPropagation,则该事件将无法到达文档,并且此侦听器将无法防止缩放行为。
禁用双击缩放类似。您需要禁用前一次点击后300毫秒内在文档中发生的任何点击:
var lastTouchEnd = 0;
document.addEventListener('touchend', function (event) {
  var now = (new Date()).getTime();
  if (now - lastTouchEnd <= 300) {
    event.preventDefault();
  }
  lastTouchEnd = now;
}, false);

如果您的表单元素设置不正确,聚焦输入框会自动缩放,由于您大多数情况下禁用了手动缩放,现在取消缩放几乎是不可能的。确保输入字体大小>= 16px。

如果您正在尝试在本机应用程序中的WKWebView中解决此问题,则上面提供的解决方案是可行的,但这是更好的解决方案:https://dev59.com/mV8e5IYBdhLWcg3wnrcQ#31943976。如其他答案中所述,在iOS 10 beta 6中,Apple现在提供了一个标志来使用meta标记。

更新于2017年5月:我用更简单的“检查touchmove上的event.scale”方法替换了旧的“在touchstart上检查触摸长度”的禁用pinch-zoom的方法。对于每个人来说应该更可靠。


7
全屏映射应用程序中,映射应用程序(如Google Maps JS、Leaflet等)中有一个硬编码的缩放功能。谷歌建议添加一个meta标签<meta name="viewport" content="initial-scale=1.0,user-scalable=no"/>,如果浏览器不遵守该meta标签,那么这是非常糟糕的浏览器设计。另外一个像非常糟糕的设计的事情是在iOS 9/10中无法防止通过滑动进行的返回/前进操作。它会严重破坏Web应用程序内部的拖动操作。 - Timo Kähkönen
4
如果用户用一只手指开始拖动,然后在屏幕上放置第二根手指,就可以使用捏合手势缩放。您可以在touchmove事件上使用preventDefault来禁用缩放和滚动。但是如果要禁用缩放,也会导致滚动被禁用(无法完全禁用缩放)。 - Paolo
14
哇,这一段(我会粘贴在这里)对我非常有帮助。我在互联网上没有看到任何其他人提到它。花了我几个小时才解决这个问题。我对苹果关于这个问题的用户体验设计选择感到非常失望,因为表单自动缩放但不缩小。如果你没有正确设置表单元素,聚焦输入框将自动缩放,由于大多数情况下手动缩放是被禁用的,现在几乎不可能取消缩放。确保输入框字体大小>= 16px. - Ryan
7
似乎这在iOS 12中不再起作用了,有什么办法可以让它在iOS 12上工作? - TJR
3
iOS 13 将 "false" 改为 "{passive: false}"。 - wayofthefuture
显示剩余13条评论

84

这是iOS 10的一个新功能。

iOS 10 beta 1发行说明中提到:

  • 为了改善Safari中网站的可访问性,即使网站在视口中设置了user-scalable=no,用户现在也可以使用捏合手势进行缩放。

我预计不久之后我们会看到一种JS插件来以某种方式禁用它。


4
@Onza: 我不认为这是坏事,我认为这是好事。禁用捏合/缩放(默认用户行为)被视为不好的做法,许多移动网站都这样做。唯一可以接受的用户案例是一个真正的 Web 应用程序,看起来和感觉像一个应用程序。 - wouterds
6
糟糕..我使用js更改了视口并仅在网站上选择某些元素时阻止缩放,现在由于这个“决定”它出了问题。如果有人决定将其阻止-一定是有原因的。 - Zhenya
12
@Karlth:对于游戏开发者来说,这非常糟糕。 - Sandeep
17
我使用IOS 10.0.2,user-scalable=no在我们网站上不再禁用缩放... 我们主要的问题是固定���边菜单时出现布局问题.. 有任何解决方案或想法吗?我知道缩放对无障碍性很有帮助,我们使用js事件(hammer)和css,在特定部分的网站上提供缩放功能.. 我不明白为什么要强制规则适用于所有人,看起来像是“电脑警察”也开始掌控我们的开发世界了?! - webkit
57
唯一可接受的使用情况将是一个看起来和感觉像应用程序的真正网络应用程序。就像你所说的那样,这是一个真正可接受的使用情况,并不是那么罕见。 - Nebula
显示剩余16条评论

27

我能够通过在单个元素上使用touch-action CSS属性来解决此问题。尝试在通常会被点击的元素(如链接或按钮)上设置touch-action: manipulation;


1
“manipulation” 不会阻止捏合缩放,只会阻止双击缩放。 - Moos
5
这应该是被采纳的答案。你可以使用 touch-action: none; 来自己控制所有手势。 - Guy Sopher
5
这很棒——禁用双击缩放,同时保留捏合缩放,这应该被视为一种手势,而双击不应该。 一只狗是一只狗。 一只狗+一只狗并不能制造出航天飞机。 它只会变成两只狗,并且它们会做你期望两只狗做的事情。 我从来没有想过两只狗会变成航天飞机。 从来没有。 - Larry
5
iOS 不支持 touch-action: none,只支持 manipulation,这样就无法解决双指缩放的问题。 - humanityANDpeace
3
使用 touch-action: pan-x pan-y 可以修复它。 - Husky931

27

在撰写本文时,在移动Safari中有效的解决方法是将addEventListener的第三个参数设置为{ passive: false },因此完整的解决方法如下:

document.addEventListener('touchmove', function (event) {
  if (event.scale !== 1) { event.preventDefault(); }
}, { passive: false });

您可能希望检查是否支持选项以保持向后兼容。


3
有人在iOS 12上尝试过吗?我添加了上面的代码,但我的Web应用程序没有任何反应。 在愚蠢的Safari中仍然可以缩放。 另外,我的meta视口标签如下所示:<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"> - Patrick DaVader
2
@PatrickDaVader 是的,在iOS 12 Safari中找不到任何可行的解决方案。对于不断缩放,我感觉晕船。 - Jamie Birch
4
这个适用于iOS 13。我的<meta>标签包括:<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, viewport-fit=cover, user-scalable=no, shrink-to-fit=no" /><meta name="HandheldFriendly" content="true"> - Sterling Bourne
1
@SterlingBourne 我复制了你的设置。它确实可以工作,但只有90%的时间。不确定为什么不是所有的时间。 - Hillcow
2
@SterlingBourne的回复对我有用!谢谢。他应该将其发布为答案而不是评论,以便可以进行投票。<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, viewport-fit=cover, user-scalable=no, shrink-to-fit=no" />和<meta name="HandheldFriendly" content="true"> - Gene Black
显示剩余4条评论

20

使用"touch-action: pan-x pan-y"可以禁用"双指缩放"和"双击缩放"功能。在我测试过的所有触摸屏幕/手机上都有效,包括iOS Safari 14.5.1。

body {
  touch-action: pan-x pan-y;
}


2
现在最佳答案。它完美地运作。 - kosmosan
它在可滚动元素上无法工作,但在不可滚动元素上可以工作,有什么可扩展的解决方案来避免滚动元素的这个问题? - Geetanshu Gulati
2
在iOS 15上无瑕疵 - Michael
1
除了 body,你还需要在任何具有 overflow: scrolloverflow: auto 属性的元素上设置它。或者只需在 * 上设置即可。 - Jo Liss
1
除了 body 外,你还需要在任何具有 overflow: scrolloverflow: auto 属性的元素上设置它。或者直接在 * 上设置。 - undefined

15

看起来这种行为在最新的测试版中已经发生了改变,写作时最新的测试版是beta 6。

iOS 10 Beta 6 的发行说明如下:

WKWebView 现在默认支持视口的 user-scalable=no 属性。 WKWebView 的客户端可以通过设置 WKWebViewConfiguration 属性中的 ignoresViewportScaleLimitsYES 来改善可访问性并允许用户对所有页面进行缩放。

然而,在我的(非常有限的)测试中,我尚不能确认是否真的如此。

编辑:验证结果,iOS 10 Beta 6 对于我来说默认支持 user-scalable=no


13
10.0.1在这里。 它没有得到尊重。苹果为什么要放弃每个人都需要的功能? - lifwanian
1
这指的是WKWebView,而不是Safari。来源:我们的一款地图应用程序出现了问题,我们完全不知道该如何修复它。 - Fabio Poloni
啊哈!抱歉,我在寻找解决WKWebView中相同的错误/功能时来到这里,并且在回答时有点假设原始问题是关于WKWebView的。因此,我想在最初的测试版之一中,苹果改变了WKWebView和移动Safari的行为,然后在beta 6中,他们恢复了WKWebView的行为,但保留了移动Safari的行为。 - Cellane
1
10.0.2不支持"user-scalable=no"。我不确定为什么他们会这样做,只是为了再次引入它,然后再次删除它。 - Aidan Hakimian

8
我花了大约一个小时寻找更强大的JavaScript选项,但没有找到。碰巧在过去的几天里,我一直在尝试使用hammer.js(Hammer.js是一个库,可以轻松地操作各种触摸事件),但大多数情况下都失败了。
有了这个警告,并且理解我绝不是JavaScript专家,这是我想出的一个解决方案,基本上利用了hammer.js来捕获pinch-zoom和double-tap事件,然后记录并丢弃它们。
确保在页面中包含hammer.js,然后尝试将此JavaScript粘贴在head中的某个位置:

< script type = "text/javascript" src="http://hammerjs.github.io/dist/hammer.min.js"> < /script >
< script type = "text/javascript" >

  // SPORK - block pinch-zoom to force use of tooltip zoom
  $(document).ready(function() {

    // the element you want to attach to, probably a wrapper for the page
    var myElement = document.getElementById('yourwrapperelement');
    // create a new hammer object, setting "touchAction" ensures the user can still scroll/pan
    var hammertime = new Hammer(myElement, {
      prevent_default: false,
      touchAction: "pan"
    });

    // pinch is not enabled by default in hammer
    hammertime.get('pinch').set({
      enable: true
    });

    // name the events you want to capture, then call some function if you want and most importantly, add the preventDefault to block the normal pinch action
    hammertime.on('pinch pinchend pinchstart doubletap', function(e) {
      console.log('captured event:', e.type);
      e.preventDefault();
    })
  });
</script>


在使用hammer.js时,我也一直在尝试解决这个问题,并且可以确认通过给所有的hammer手势处理器添加.preventDefault的方式来阻止视口缩放。我同时在使用滑动/捏合/平移/点击等手势,将其添加到了所有的处理器上,我不确定是哪个具体的手势起到了作用。 - Conan

8

在我的情况下,我正在使用Babylon.js创建一个3D场景,我的整个页面由一个全屏画布组成。 3D引擎具有自己的缩放功能,但在iOS上,捏合缩放会干扰它。 我更新了@Joseph的答案以解决我的问题。为了禁用它,我发现需要将{passive: false}作为选项传递给事件侦听器。以下代码对我有效:

window.addEventListener(
    "touchmove",
    function(event) {
        if (event.scale !== 1) {
            event.preventDefault();
        }
    },
    { passive: false }
);

我的使用案例也是一个带有自定义捏合控件的全屏3D场景。如果没有绕过苹果明确忽略用户缩放的方法,我就会失败了:没有元标记。 - Nick Bilyk
1
救命稻草-这是唯一一个在iOS 14.4.2上仍然允许注册多点触控的解决方案,对我来说非常有效-我的用例是一个使用移动杆控件的网页游戏。 - David Bradbury

7
我们可以通过注入一个样式规则和拦截缩放事件来实现我们想要的一切:
$(function () {
  if (!(/iPad|iPhone|iPod/.test(navigator.userAgent))) return
  $(document.head).append(
    '<style>*{cursor:pointer;-webkit-tap-highlight-color:rgba(0,0,0,0)}</style>'
  )
  $(window).on('gesturestart touchmove', function (evt) {
    if (evt.originalEvent.scale !== 1) {
      evt.originalEvent.preventDefault()
      document.body.style.transform = 'scale(1)'
    }
  })
})

✔ 禁用捏合缩放。

✔ 禁用双击缩放。

✔ 滚动不受影响。

✔ 禁用轻击高亮(在iOS上由样式规则触发)。

注意:根据您的喜好调整iOS检测。有关更多信息,请单击此处


对于出现在上面代码中的lukejackson和Piotr Kowalski,我们表示歉意,其答案已被修改。


这在我的运行iOS 11.2的iPad模拟器上可以工作。但在我运行iOS 11.3的真实iPad上无法工作。我添加了console.log以确保事件被触发并出现在控制台中。这是与iOS 11.3有关吗?还是与真实设备有关? - Mathieu R.
1
@MathieuR。这是一个iOS 11.3的问题。可以通过使用基于addEventListener的答案之一并将{passive:false}作为options参数传递来纠正它,而不是false。但是,为了向后兼容,除非支持passive选项字段,否则需要传递false。请参见https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Improving_scrolling_performance_with_passive_listeners - Josh Gallagher
@JoshGallagher,你能提供一个可行的例子吗?在iOS11上,所有的答案都对我无效。 - Mick
“gesturestart” -> preventDefault 在我撰写本文时在 iOS 12.2 上可行。 - Michael Camden

6

我想出了一个相当朴素的解决方案,但它似乎起作用了。 我的目标是防止意外的双击被解释为缩放,同时保持捏合缩放对无障碍性的工作。

这个想法是在双击中测量第一个 touchstart 和第二个 touchend 之间的时间,如果延迟时间过短,则将最后一个 touchend 解释为单击。虽然可以防止意外的缩放,但这种方法似乎能保持列表滚动不受影响,这很好。不确定是否漏掉了什么。

let preLastTouchStartAt = 0;
let lastTouchStartAt = 0;
const delay = 500;

document.addEventListener('touchstart', () => {
  preLastTouchStartAt = lastTouchStartAt;
  lastTouchStartAt = +new Date();
});
document.addEventListener('touchend', (event) => {
  const touchEndAt = +new Date();
  if (touchEndAt - preLastTouchStartAt < delay) {
    event.preventDefault();
    event.target.click();
  }
});

受到mutewinter的代码片段Joseph的回答的启发。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接