programing

iOS Safari – 오버스크롤을 비활성화하면서 스크롤 가능한 div를 정상적으로 스크롤할 수 있도록 하는 방법은 무엇입니까?

lastmoon 2023. 9. 4. 20:33
반응형

iOS Safari – 오버스크롤을 비활성화하면서 스크롤 가능한 div를 정상적으로 스크롤할 수 있도록 하는 방법은 무엇입니까?

저는 아이패드 기반의 웹 앱을 만들고 있는데, 웹 페이지처럼 보이지 않도록 과도한 스크롤을 방지해야 합니다.현재 이 기능을 사용하여 뷰포트를 고정하고 오버스크롤을 사용하지 않습니다.

document.body.addEventListener('touchmove',function(e){
      e.preventDefault();
  });

이것은 오버스크롤을 비활성화하는 데 효과적이지만 내 앱에는 스크롤 가능한 디브가 여러 개 있으며코드는 스크롤할없도록 합니다.

저는 iOS 5 이상만 대상으로 하고 있기 때문에 iScroll과 같은 해킹 솔루션은 피했습니다.대신 스크롤 가능한 div를 위해 이 CSS를 사용합니다.

.scrollable {
    -webkit-overflow-scrolling: touch;
    overflow-y:auto;
}

이것은 문서 오버스크롤 스크립트 없이 작동하지만 디비 스크롤 문제를 해결하지는 못합니다.

jQuery 플러그인이 없으면 오버스크롤 수정을 사용하지 않고 $(.scrollable) div를 면제할 수 있는 방법이 있습니까?

편집:

적절한 해결책을 찾았습니다.

 // Disable overscroll / viewport moving on everything but scrollable divs
 $('body').on('touchmove', function (e) {
         if (!$('.scrollable').has($(e.target)).length) e.preventDefault();
 });

디브의 시작이나 끝을 스크롤해도 뷰포트가 계속 이동합니다.저는 그것도 비활성화할 수 있는 방법을 찾고 싶습니다.

이렇게 하면 디브의 시작 또는 끝을 스크롤할 때 문제가 해결됩니다.

var selScrollable = '.scrollable';
// Uses document because document will be topmost level in bubbling
$(document).on('touchmove',function(e){
  e.preventDefault();
});
// Uses body because jQuery on events are called off of the element they are
// added to, so bubbling would not work if we used document instead.
$('body').on('touchstart', selScrollable, function(e) {
  if (e.currentTarget.scrollTop === 0) {
    e.currentTarget.scrollTop = 1;
  } else if (e.currentTarget.scrollHeight === e.currentTarget.scrollTop + e.currentTarget.offsetHeight) {
    e.currentTarget.scrollTop -= 1;
  }
});
// Stops preventDefault from being called on document if it sees a scrollable div
$('body').on('touchmove', selScrollable, function(e) {
  e.stopPropagation();
});

div에 오버플로가 없을 때 전체 페이지 스크롤을 차단하려는 경우에는 이 기능이 작동하지 않습니다.이를 차단하려면 바로 위의 이벤트 핸들러 대신 다음 이벤트 핸들러를 사용합니다(이 질문에서 수정됨).

$('body').on('touchmove', selScrollable, function(e) {
    // Only block default if internal div contents are large enough to scroll
    // Warning: scrollHeight support is not universal. (https://stackoverflow.com/a/15033226/40352)
    if($(this)[0].scrollHeight > $(this).innerHeight()) {
        e.stopPropagation();
    }
});

Tyler Dodge의 훌륭한 답변을 사용하여 iPad에서 계속 렉이 걸려서 조절 코드를 추가했는데, 지금은 꽤 매끄럽습니다.스크롤하는 동안 약간의 최소한의 건너뛰기가 있습니다.

// Uses document because document will be topmost level in bubbling
$(document).on('touchmove',function(e){
  e.preventDefault();
});

var scrolling = false;

// Uses body because jquery on events are called off of the element they are
// added to, so bubbling would not work if we used document instead.
$('body').on('touchstart','.scrollable',function(e) {

    // Only execute the below code once at a time
    if (!scrolling) {
        scrolling = true;   
        if (e.currentTarget.scrollTop === 0) {
          e.currentTarget.scrollTop = 1;
        } else if (e.currentTarget.scrollHeight === e.currentTarget.scrollTop + e.currentTarget.offsetHeight) {
          e.currentTarget.scrollTop -= 1;
        }
        scrolling = false;
    }
});

// Prevents preventDefault from being called on document if it sees a scrollable div
$('body').on('touchmove','.scrollable',function(e) {
  e.stopPropagation();
});

또한 다음 CSS를 추가하면 일부 렌더링 결함(소스)이 수정됩니다.

.scrollable {
    overflow: auto;
    overflow-x: hidden;
    -webkit-overflow-scrolling: touch;
}
.scrollable * {
    -webkit-transform: translate3d(0,0,0);
}

먼저 일반적인 경우처럼 전체 문서에서 기본 수행을 방지합니다.

$(document).bind('touchmove', function(e){
  e.preventDefault();           
});

그런 다음 요소 클래스가 문서 수준으로 전파되는 것을 중지합니다.그러면 위의 기능에 도달할 수 없으므로 e.proventDefault()가 시작되지 않습니다.

$('.scrollable').bind('touchmove', function(e){
  e.stopPropagation();
});

이 시스템은 모든 터치 동작에서 클래스를 계산하는 것보다 더 자연스럽고 덜 집중적인 것처럼 보입니다.동적으로 생성된 요소에는 .bind() 대신 .on()을 사용합니다.

스크롤 가능한 div를 사용하는 동안 불행한 일이 발생하지 않도록 다음 메타 태그도 고려하십시오.

<meta content='True' name='HandheldFriendly' />
<meta content='width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0' name='viewport' />
<meta name="viewport" content="width=device-width" />

오버스크롤 비활성화 코드에 논리를 조금 더 추가하여 문제의 대상 요소가 스크롤하려는 요소가 아닌지 확인할 수 있습니까?이와 같은 것:

document.body.addEventListener('touchmove',function(e){
     if(!$(e.target).hasClass("scrollable")) {
       e.preventDefault();
     }
 });

이것에 대한 가장 좋은 해결책은 css/html입니다. 만약 당신이 아직 그것을 가지고 있지 않다면, 당신의 요소를 랩할 div를 만들고 그것을 고정된 위치로 설정하고 오버플로를 숨깁니다.옵션, 화면 전체를 채우고 화면 전체만 채우려면 높이와 너비를 100%로 설정합니다.

#wrapper{
  height: 100%;
  width: 100%;
  position: fixed;
  overflow: hidden;
}
<div id="wrapper">
  <p>All</p>
  <p>Your</p>
  <p>Elements</p>
</div>

위로 스크롤을 시도할 때 스크롤 가능한 요소가 이미 위쪽으로 스크롤되었는지 또는 아래쪽으로 스크롤을 시도할 때 스크롤 가능한 요소가 이미 스크롤되어 있는지 확인하고 전체 페이지 이동을 중지하는 기본 작업을 방지합니다.

var touchStartEvent;
$('.scrollable').on({
    touchstart: function(e) {
        touchStartEvent = e;
    },
    touchmove: function(e) {
        if ((e.originalEvent.pageY > touchStartEvent.originalEvent.pageY && this.scrollTop == 0) ||
            (e.originalEvent.pageY < touchStartEvent.originalEvent.pageY && this.scrollTop + this.offsetHeight >= this.scrollHeight))
            e.preventDefault();
    }
});

스크롤 가능한 영역이 있는 팝업(카트의 스크롤 가능 보기가 있는 "쇼핑 카트" 팝업)이 나타날 때 모든 신체 스크롤을 방지하는 방법을 찾고 있었습니다.

나는 당신이 스크롤하고 싶은 팝업이나 디브가 있을 때 당신의 몸에서 클래스 "noscroll"을 전환하기 위해 미니멀 자바스크립트를 사용하여 훨씬 더 우아한 솔루션을 작성했습니다.

데스크톱 브라우저가 오버플로를 관찰하는 동안: 숨김 -- 위치를 수정으로 설정하지 않는 한 iOS는 이를 무시하는 것 같습니다.페이지 전체가 이상한 너비가 되므로 위치와 너비도 수동으로 설정해야 합니다.다음 CSS 사용:

.noscroll {
    overflow: hidden;
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
}

그리고 이 농담은.

/* fade in/out cart popup, add/remove .noscroll from body */
$('a.cart').click(function() {
    $('nav > ul.cart').fadeToggle(100, 'linear');
    if ($('nav > ul.cart').is(":visible")) {
        $('body').toggleClass('noscroll');
    } else {
        $('body').removeClass('noscroll');
    }
});

/* close all popup menus when you click the page... */
$('body').click(function () {
    $('nav > ul').fadeOut(100, 'linear');
    $('body').removeClass('noscroll');
});

/* ... but prevent clicks in the popup from closing the popup */
$('nav > ul').click(function(event){
    event.stopPropagation();
});

저는 농담 없이 일을 좀 했습니다.완벽하지는 않지만 잘 작동합니다(특히 스콜리에 스크롤-x가 있는 경우) https://github.com/pinadesign/overscroll/

자유롭게 참여하고 개선할 수 있습니다.

이 솔루션은 스크롤 가능한 모든 div에 스크롤 가능한 클래스를 배치할 필요가 없으므로 더 일반적입니다.스크롤은 INPUT 요소 컨텐츠 편집 가능한 모든 요소와 오버플로 스크롤 또는 자동에 대해 허용됩니다.

사용자 지정 선택기를 사용하고 검사 결과를 요소에 캐시하여 성능을 향상시킵니다.매번 동일한 요소를 확인할 필요가 없습니다.이것은 방금 작성되었지만 공유하려고 생각했던 것과 같은 몇 가지 문제가 있을 수 있습니다.

$.expr[':'].scrollable = function(obj) {
    var $el = $(obj);
    var tagName = $el.prop("tagName");
    return (tagName !== 'BODY' && tagName !== 'HTML') && (tagName === 'INPUT' || $el.is("[contentEditable='true']") || $el.css("overflow").match(/auto|scroll/));
};
function preventBodyScroll() {
    function isScrollAllowed($target) {
        if ($target.data("isScrollAllowed") !== undefined) {
            return $target.data("isScrollAllowed");
        }
        var scrollAllowed = $target.closest(":scrollable").length > 0;
        $target.data("isScrollAllowed",scrollAllowed);
        return scrollAllowed;
    }
    $('body').bind('touchmove', function (ev) {
        if (!isScrollAllowed($(ev.target))) {
            ev.preventDefault();
        }
    });
}

모든 "터치 이동" 이벤트를 비활성화하는 것이 좋습니다. 페이지에 스크롤 가능한 다른 요소가 필요한 즉시 문제가 발생합니다.또한 특정 요소(예: 페이지를 스크롤할 수 없도록 하려면 본문)에서만 "터치 이동" 이벤트를 비활성화하면 URL 표시줄이 전환될 때 IOS는 즉시 Chrome에서 중단할 수 없는 전파를 발생시킵니다.

이 행동을 설명할 수는 없지만, 예방할 수 있는 유일한 방법은 신체의 위치를fixed유일한 문제는 문서의 위치를 잃는다는 것입니다. 예를 들어 모델에서는 특히 짜증이 납니다.그것을 해결하는 한 가지 방법은 이 간단한 바닐라를 사용하는 것입니다.JS 기능:

function disableDocumentScrolling() {
    if (document.documentElement.style.position != 'fixed') {
        // Get the top vertical offset.
        var topVerticalOffset = (typeof window.pageYOffset != 'undefined') ?
            window.pageYOffset : (document.documentElement.scrollTop ? 
            document.documentElement.scrollTop : 0);
        // Set the document to fixed position (this is the only way around IOS' overscroll "feature").
        document.documentElement.style.position = 'fixed';
        // Set back the offset position by user negative margin on the fixed document.
        document.documentElement.style.marginTop = '-' + topVerticalOffset + 'px';
    }
}

function enableDocumentScrolling() {
    if (document.documentElement.style.position == 'fixed') {
        // Remove the fixed position on the document.
        document.documentElement.style.position = null;
        // Calculate back the original position of the non-fixed document.
        var scrollPosition = -1 * parseFloat(document.documentElement.style.marginTop);
        // Remove fixed document negative margin.
        document.documentElement.style.marginTop = null;
        // Scroll to the original position of the non-fixed document.
        window.scrollTo(0, scrollPosition);
    }
}

이 솔루션을 사용하면 당신은 고정된 문서를 가질 수 있고 당신의 페이지에 있는 다른 요소들은 간단한 CSS를 사용함으로써 오버플로우 될 수 있습니다.overflow: scroll;) 특별한 수업이나 다른 것이 필요 없습니다.

호환 가능한 솔루션에 대한 자세한 내용은 다음과 같습니다.

    if (!$(e.target).hasClass('scrollable') && !$(e.target).closest('.scrollable').length > 0) {
       console.log('prevented scroll');
       e.preventDefault();
       window.scroll(0,0);
       return false;
    }

이것은 나를 위해 작동합니다 (자바스크립트 포함)

var fixScroll = function (className, border) {  // className = class of scrollElement(s), border: borderTop + borderBottom, due to offsetHeight
var reg = new RegExp(className,"i"); var off = +border + 1;
function _testClass(e) { var o = e.target; while (!reg.test(o.className)) if (!o || o==document) return false; else o = o.parentNode; return o;}
document.ontouchmove  = function(e) { var o = _testClass(e); if (o) { e.stopPropagation(); if (o.scrollTop == 0) { o.scrollTop += 1; e.preventDefault();}}}
document.ontouchstart = function(e) { var o = _testClass(e); if (o && o.scrollHeight >= o.scrollTop + o.offsetHeight - off) o.scrollTop -= off;}
}

fixScroll("fixscroll",2); // assuming I have a 1px border in my DIV

html:

<div class="fixscroll" style="border:1px gray solid">content</div>

이것을 사용해 보세요. 완벽하게 작동할 것입니다.

$('body.overflow-hidden').delegate('#skrollr-body','touchmove',function(e){
    e.preventDefault();
    console.log('Stop skrollrbody');
}).delegate('.mfp-auto-cursor .mfp-content','touchmove',function(e){
    e.stopPropagation();
    console.log('Scroll scroll');
});

저는 단순함으로 놀라운 행운을 얻었습니다.

body {
    height: 100vh;
}

팝업이나 메뉴에 대해 오버스크롤을 사용하지 않도록 설정하면 효과적이며 position:fixed를 사용할 때처럼 브라우저 표시줄이 강제로 나타나지 않습니다.그러나 - 고정 높이를 설정하기 전에 스크롤 위치를 저장하고 팝업을 숨길 때 복원해야 합니다. 그렇지 않으면 브라우저가 맨 위로 스크롤됩니다.

overscroll-behavior: none;

오버스크롤

오버스크롤 동작 속성은 컨테이너(페이지 자체 포함)를 오버스크롤할 때 발생하는 동작을 제어하는 새로운 CSS 기능입니다.이 기능을 사용하여 스크롤 체인을 취소하고, 풀 투 리프레시 작업을 비활성화/사용자 지정하고, iOS에서 고무 밴딩 효과를 비활성화할 수 있습니다(Safari가 오버스크롤 동작을 구현할 때).가장 좋은 점은 오버스크롤 동작을 사용하면 페이지 성능에 악영향을 미치지 않는다는 것입니다.

언급URL : https://stackoverflow.com/questions/10238084/ios-safari-how-to-disable-overscroll-but-allow-scrollable-divs-to-scroll-norma

반응형