最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - disabling bouncy scrolling only for html but maintaining for elements with overflow:scroll - Stack Overflow

programmeradmin1浏览0评论

I am creating a full screen web app which will have some modules/widgets which make use of the new iOS 5 overflow:scroll features. What I want is to disable that 'bouncy' effect when scrolling the html/body (since it is full screen) but keep that effect only on the scrollable elements.

to smooth the effects of scrollable elements I have:

html, body { overflow: hidden; }

.scrollable {
    overflow: scroll;
    -webkit-overflow-scrolling: touch;
}

and then the following script which disables the touch scroll effect:

$(document).bind('touchmove', function (e) { 
    if (e.target === document.documentElement) {
        e.preventDefault(); 
    }
});

although this doesn't seem to work at all, because when scrolling an element to very bottom end or top it also scrolls the documentElement.

Is there any way to only disable that effect for the body html element?

Here it is a good example of how this affects the functionality:

.html

I am creating a full screen web app which will have some modules/widgets which make use of the new iOS 5 overflow:scroll features. What I want is to disable that 'bouncy' effect when scrolling the html/body (since it is full screen) but keep that effect only on the scrollable elements.

to smooth the effects of scrollable elements I have:

html, body { overflow: hidden; }

.scrollable {
    overflow: scroll;
    -webkit-overflow-scrolling: touch;
}

and then the following script which disables the touch scroll effect:

$(document).bind('touchmove', function (e) { 
    if (e.target === document.documentElement) {
        e.preventDefault(); 
    }
});

although this doesn't seem to work at all, because when scrolling an element to very bottom end or top it also scrolls the documentElement.

Is there any way to only disable that effect for the body html element?

Here it is a good example of how this affects the functionality:

http://dl.dropbox./u/1928164/ios5/index.html

Share Improve this question edited Nov 10, 2011 at 23:36 zanona asked Nov 8, 2011 at 15:33 zanonazanona 12.7k25 gold badges90 silver badges146 bronze badges 5
  • I don't think your event handler will ever hit preventDefault() because target is the element that triggered the event, which can never be document.documentElement (<html>). So you're seeing the same behavior as if you didn't have the event handler. – ThinkingStiff Commented Nov 10, 2011 at 21:23
  • that would be currentTarget I'm afraid. target can return anything inside it, you might want to try ;) – zanona Commented Nov 10, 2011 at 23:32
  • currentTarget returns the element with the listener, not the element that threw the event. – ThinkingStiff Commented Nov 10, 2011 at 23:36
  • ah I see your point, thats correct. I tried with body too without sucess. I will play with the code on your answer and let you know how it goes, thanks man – zanona Commented Nov 10, 2011 at 23:39
  • I was just writing this demo before your last ment: jsfiddle/ThinkingStiff/3TkuF – ThinkingStiff Commented Nov 10, 2011 at 23:46
Add a ment  | 

3 Answers 3

Reset to default 2

It's unfortunate that -webkit-overflow-scrolling doesn't handle this better. You need to track the y position to make it work. I put the class scroll on anything I want to scroll on my page, such as <ul> elements. Wrap a <div> around the <ul> that fills the viewport with overflow-y: auto. Don't put overflow or height on the <ul>. The <ul> will expand as tall as its contents and it's the <div> that is actually doing the scrolling. -webkit-overflow-scrolling is inherited, so put it as far up the DOM as you want.

Demo: http://jsfiddle/ThinkingStiff/FDqH7/

Script:

var swipeY = 0;

function onTouchMove( event ) {

    var scroll = event.target.closestByClassName( 'scroll' );

    if ( scroll ) {

        var top = scroll.positionTop - scroll.parentNode.positionTop,
            heightDifference = ( 0 - scroll.offsetHeight + scroll.parentNode.offsetHeight );

        if( ( top >= 0 ) && ( event.touches[0].screenY > swipeY ) ) { 
            event.preventDefault(); //at top, swiping down
        } else if( ( top <= heightDifference ) && ( event.touches[0].screenY < swipeY ) ) { 
            event.preventDefault(); //at bottom, swiping up
        };

    } else {
        event.preventDefault();
    };

};

function onTouchStart( event ) {

    swipeY = event.touches[0].screenY;

};

Element.prototype.closestByClassName = function ( className ) {

    return this.className && this.className.split( ' ' ).indexOf( className ) > -1
        ? this
        : ( this.parentNode.closestByClassName && this.parentNode.closestByClassName( className ) );

};

window.Object.defineProperty( Element.prototype, 'positionTop', {

    get: function () { 
        return this.offsetTop - this.parentNode.scrollTop;
    }

} );

document.getElementById( 'viewport' ).addEventListener( 'touchmove', onTouchMove, false );
document.getElementById( 'viewport' ).addEventListener( 'touchstart', onTouchStart, false );

HTML:

<div id="viewport">
<div id="scroll-view">
    <ul class="scroll">
        <li>scroll scroll scroll scroll scroll </li>
        <li>scroll scroll scroll scroll scroll </li>
        <li>scroll scroll scroll scroll scroll </li>

        . . .

    </ul>
</div>
</div>

CSS:

#viewport {
    border: 1px solid black;
    height: 460px;
    width: 320px;
    -webkit-overflow-scrolling: touch;
}

#scroll-view {
    height: 100%;
    overflow-y: auto;
    width: 100%;
}

Here's a similar answer to ThinkingStiff's, except that it doesn't mandate your html structure. It looks for any elements that have overflowed content and enables scrolling only when the user is interacting with them.

Downsides:

  • Once the user hits the top or bottom limit of the scrollable node, bouncing within that node will not occur (but it will if you flick from below/above the limits). This probably means that it does not satisfy your requirements for pull to refresh :(

  • There's an odd 2px difference that I noticed in my test cases when calculating scroll offsets. Not sure where that came from, and you might need to tweak the value

CoffeeScript:

# Vertical scrolling behavior overrides.
#
# This disables vertical scrolling on the page for touch devices, unless the user is scrolling
# within an overflowed node.  This requires some finessing of the touch events.
#
# **NOTE:** This code ends up disabling bounce behavior if the user tries to scroll on a node that
# is already at its upper or lower limit.
window$   = $(window)
initialY  = null
nodeStack = []

# When a user begins a (potential) drag, we jot down positional and node information.
#
# The assumption is that page content isn't going to move for the duration of the drag, and that
# it would also be awkward if the drag were to change/stop part way through due to DOM
# modifications.
window$.bind 'touchstart', (evt) ->
  initialY  = evt.originalEvent.pageY
  nodeStack = $(evt.target).parents().andSelf().filter(':not(body, html)').get().reverse()
  nodeStack = nodeStack.map (node) -> $(node)

window$.bind 'touchend touchcancel', (evt) ->
  initialY  = null
  nodeStack = []

# We override the `touchmove` event so that we only allow scrolls in allowable directions,
# depending on where the user first began the drag.
window$.bind 'touchmove', (evt) ->
  return evt.preventDefault() if initialY == null
  # A positive direction indicates that the user is dragging their finger down, thus wanting the
  # content to scroll up.
  direction = evt.originalEvent.pageY - initialY

  for node$ in nodeStack
    nodeHeight    = node$.height()
    # For some reason, the node's scrollHeight is off by 2 pixels in all cases.  This may require
    # tweaking depending on your DOM.  Concerning.
    scrollHeight  = node$[0].scrollHeight - 2
    nodeScrollTop = node$.scrollTop()

    # If we have a scrollable element, we want to only allow drags under certain circumstances:
    if scrollHeight > nodeHeight
      # * The user is dragging the content up, and the element is already scrolled down a bit.
      return if direction > 0 and nodeScrollTop > 0
      # * And the reverse: the user is dragging the content down, and the element is up a bit.
      return if direction < 0 and nodeScrollTop < scrollHeight - nodeHeight

  # Otherwise, the default behavior is to disable dragging.
  evt.preventDefault()

It turns out for me that the only effective solution was to use joelambert/ScrollFix script, worked really well with no lags, In fact I am already using it in one of my projects.

You can also check about it in more details on his blog post. Sorry for the other users who replied but I really didn't get those answers to work for me.

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论