4

How it's expected to work

I created a scollable div for a project. The position of the scrollbar is calculated width jQuery. In a desktop environment there is a visible slider. On mobile devices there is not but it's still possible to swipe left to get more content.

(It does not yet update on window resize. Reload is required.)

Expected: "overflow_diff" should be equal to "Scoll pos". "Percentage" should be 100 when scolled to the end.

What works

It works fine in Chrome and Firefox on desktop and on Chrome on Android.

What does not work - My question

Firefox on Android does the calculations all wrong. Strange is that it works on desktop. If it's a bug in Firefox, how do I get around it?

Full example

http://xn--trnell-wxa.se/scrolltest2/index.php

HTML header

<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>

CSS

* {
        padding: 0;
        margin: 0;
    }
    .wrap {
        padding: 40px;
        background: #eee;
        width: 75%;
    }
    .cropped {
        overflow-x: auto;
    }
    .overflow {
        width: 300%;
        background: #ddd;
        height: 100px;
    }

JS

jQuery(window).ready(function($) {
        var cropped_width = $('.cropped').width();
        var overflow_width = $('.overflow').width();
        var overflow_diff = overflow_width - cropped_width;

        $( '.log' ).append( 'Overflow: ' + overflow_width + '<br>' );
        $( '.log' ).append( 'Cropped: ' + cropped_width + '<br>' );
        $( '.log' ).append( 'Overflow diff: ' + overflow_diff + '<br>' );
        $( '.log' ).append( '<div class="scrolled"></div>' );
        $( '.log' ).append( '<div class="scrolled2"></div>' );

        $( '.cropped' ).on('scroll touchmove', function() {
            var scroll_pos = $( this ).scrollLeft();
            var percentage = Math.round( scroll_pos / overflow_diff * 100 );

            $( '.log .scrolled' ).html( 'Scroll pos: ' + scroll_pos + '<br>Percentage: ' + percentage + '<br>' );
        });
    });

HTML

<div class="wrap">
    <div class="cropped">
        <div class="overflow">Swipe to the end</div>
    </div>
</div>
<div class="log"></div>
Jens Törnell
  • 23,180
  • 45
  • 124
  • 206
  • I doubt that it's doing the math incorrectly, which means that either `$( this ).scrollLeft()` is wrong or a width has changed and `overflow_diff` is now wrong. What happens if you recalculate overflow_diff inside the event handler and then log those two values? – James Jan 18 '15 at 16:48

2 Answers2

1

I think you should bind your event with .on() and use touchmove event too:

$( '.cropped' ).on('scroll touchmove', function() {
    // the code here
});
Jai
  • 74,255
  • 12
  • 74
  • 103
0

From @Joeytje50 answer Android browsers not handling touchmove events correctly

Turns out the problem here was simply the fact the event handler didn't have an event.preventDefault() in it, so the original action still executed, which apparently interrupted the touch event. To fix this, simply add e.preventDefault() in the current event handler function to cancel the current event, and make it work as expected in Chrome and Opera too.

Also, to check whether you use scroll or touchmove you can use the below condition,

// ..... your remaining code
$( '.log' ).append( '<div class="scrolled2"></div>' );

var eventName='scroll';
if ('ontouchstart' in document.documentElement) {
    eventName = 'touchmove';
}
$( '.cropped' ).on(eventName , function(e) {
    (eventName == 'touchmove') ? e.preventDefault() : '';
    var scroll_pos = $( this ).scrollLeft();
    // your remaining code
});
Community
  • 1
  • 1
Rohan Kumar
  • 40,431
  • 11
  • 76
  • 106