iOS 17 Safari移动端body设置overflow:hidden无效的拖拽滚动问题
iOS 17 Safari下拖拽排序时页面滚动无法禁止的解决方案
问题描述
在网站帖子编辑功能中实现图片拖拽排序,为避免拖拽时页面滚动干扰,给body添加overflow:hidden属性。该设置在桌面端、Mac及Android平台均正常,但在iOS 17的Safari移动端无效。
尝试过的无效方案:
- 添加
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1"> - 设置CSS样式
html, body {position: relative, overflow: hidden}
当前核心问题:iOS手机Safari中拖拽图片时,上下拖动会触发页面滚动,严重干扰拖拽定位,无法将图片放到目标位置。
现有实现代码
function touchHandler(event) { var touch = event.changedTouches[0]; var simulatedEvent = document.createEvent("MouseEvent"); simulatedEvent.initMouseEvent({ touchstart: "mousedown", touchmove: "mousemove", touchend: "mouseup" }[event.type], true, true, window, 1, touch.screenX, touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null); touch.target.dispatchEvent(simulatedEvent); // event.preventDefault(); } function init() { document.addEventListener("touchstart", touchHandler, true); document.addEventListener("touchmove", touchHandler, true); document.addEventListener("touchend", touchHandler, true); document.addEventListener("touchcancel", touchHandler, true); } function unInit() { document.removeEventListener("touchstart", touchHandler, true); document.removeEventListener("touchmove", touchHandler, true); document.removeEventListener("touchend", touchHandler, true); document.removeEventListener("touchcancel", touchHandler, true); } init(); // 排序功能 function sortContent(_elm, callback = null) { if ($(_elm).length) { var _listArray = []; for (var _i = 0; _i < $(_elm).find('.sort_item').length; _i++) { _listArray[_i] = $(_elm).find('.sort_item').eq(_i).attr('id').replace('list_', ''); } $(_elm).sortable({ 'start': function () { // $('body').css('overflow', 'hidden'); if (/iPad|iPhone|iPod/.test(navigator.userAgent)) { $('html, body').css({'position': 'relative', 'overflow': 'hidden'}); } document.ontouchmove = function (e) { e.preventDefault(); }; }, "opacity": 0.5, // 拖拽中的透明度 "update": function (event, ui) { // 拖拽完成后的回调 for (var _i = 0; _i < $(_elm).find('.sort_item').length; _i++) { var _sort = $(_elm).find('.sort_item').eq(_i).attr('id').replace('list_', ''); _listArray[_i] = _sort; } var numberOrder = 1; $('.ui-sortable .sort_item').each(function () { $(this).find('.order-number').text(numberOrder); numberOrder++; }); }, 'stop': function () { // $('body').css('overflow', 'auto'); if (/iPad|iPhone|iPod/.test(navigator.userAgent)) { $('html, body').css('overflow', 'auto'); } document.ontouchmove = function () { return true; }; } }); } } sortContent('.list_images_wrapper .list_images > ul');
解决方案
针对iOS 17 Safari的滚动机制特性,调整以下3点即可解决问题:
1. 替换position: relative为position: fixed
iOS Safari对html/body设置overflow:hidden时,position:relative无法完全阻止原生滚动,改用fixed并记录当前滚动位置,拖拽结束后恢复:
'start': function () { if (/iPad|iPhone|iPod/.test(navigator.userAgent)) { // 记录当前滚动位置 const scrollTop = window.pageYOffset || document.documentElement.scrollTop; $('html, body').css({ 'position': 'fixed', 'overflow': 'hidden', 'top': `-${scrollTop}px`, 'width': '100%' }); } else { $('body').css('overflow', 'hidden'); } document.ontouchmove = function (e) { e.preventDefault(); }; }, 'stop': function () { if (/iPad|iPhone|iPod/.test(navigator.userAgent)) { // 恢复滚动位置 const scrollTop = parseInt($('html').css('top')) * -1; $('html, body').css({ 'position': '', 'overflow': '', 'top': '', 'width': '' }); window.scrollTo(0, scrollTop); } else { $('body').css('overflow', 'auto'); } document.ontouchmove = function () { return true; }; }
2. 精准控制preventDefault触发时机
在touchHandler中,仅当拖拽目标是排序项或其父容器时,才阻止默认滚动行为,避免影响页面其他交互:
function touchHandler(event) { var touch = event.changedTouches[0]; var simulatedEvent = document.createEvent("MouseEvent"); simulatedEvent.initMouseEvent({ touchstart: "mousedown", touchmove: "mousemove", touchend: "mouseup" }[event.type], true, true, window, 1, touch.screenX, touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null); touch.target.dispatchEvent(simulatedEvent); // 仅针对排序相关元素阻止滚动 if (event.type === 'touchmove' && $(touch.target).closest('.sort_item, .ui-sortable').length) { event.preventDefault(); } }
3. 添加webkit专属CSS限制
补充CSS禁用iOS Safari的弹性滚动,强制浏览器遵循自定义触摸规则:
@media only screen and (max-width: 767px) and (-webkit-min-device-pixel-ratio: 1) { html, body { -webkit-overflow-scrolling: auto !important; } .ui-sortable { touch-action: none; } }
原理说明
- iOS Safari依赖webkit原生滚动机制,
position:fixed能强制固定页面,彻底阻断滚动触发; touch-action: none告诉浏览器无需处理排序容器的触摸滚动行为,交由自定义事件逻辑处理;- 精准控制
preventDefault的触发范围,避免破坏页面其他正常交互。
内容的提问来源于stack exchange,提问作者Ngọc Đồ Đinh
相关产品推荐
相关产品推荐

