You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 13:34:59