@garryyao
A touch scrolling implementation in JavaScript that compares to native experience
The most frequently used interaction on the planet is perhaps...
The elements that makes a comprehensive native scrolling experience :
Q: How to avoid page from scrolling on a mobile device?
html, body {
height: 100%;
}
body {
overflow-y: hidden;
}
Q: How to avoid page from scrolling on a mobile device?
<meta name="viewport"
content="width=device-width, user-scalable=no">
Q: How to avoid page from scrolling on a mobile device?
This will ONLY disable the pinch–and–zoom effect as expected.
but if you swipe vertically...you’ll end up seeing a random bar
Q: How to avoid page from scrolling on a mobile device?
document.addEventListener('touchmove', function(e) {
e.preventDefault();
}, false);
But it also prevent any other overflowed element from scrolling!
Q: How to avoid page from scrolling on a mobile device?
$(document).bind('touchmove', function(e) {
if(!$(e.target).parent('.content').length){
e.preventDefault();
}
});
It works until you have reached the end of the inner scroll, then it will scroll the window!
Q: how to animate along with touch scrolling on mobile device, aka. the scroll event?
Sorry you can't...
most of the mobile browsers just doesn't fire the "scroll" event the way you expect
this.state = {
// aka. scrollTop
topPosition: 0,
// aka. scrollLeft
leftPosition: 0,
// aka. scrollHeight
realHeight: 0,
// aka. clientHeight
containerHeight: 0,
// aka. scrollWidth
realWidth: 0,
// aka. clientWidth
containerWidth: 0,
// if content has horizontally overflowed
scrollableX: false,
// if content has vertically overflowed
scrollableY: false
};
handleWheel(e) {
var newState = this.computeSizes();
var deltaY = e.deltaY * this.props.speed;
var deltaX = e.deltaX * this.props.speed;
if (this.canScrollY(newState)) {
newState.topPosition = this.computeTopPosition(-deltaY);
}
if (this.canScrollX(newState)) {
newState.leftPosition = this.computeLeftPosition(-deltaX);
}
this.setState(newState);
}
render() {
var style = {
marginTop: this.state.topPosition,
marginLeft: this.state.leftPosition
};
return (
<div>
<div className="content" style={style} >
{this.props.children}
</div>
</div>
);
}
in condition of not to consider performance & usability
Er...but what's the performance issue that you're worrying about?
Perform the scrolling using CSS3 transform: translate(z, y, x) to makes it much faster since there's no repaint happened when you scroll
var scrollbarY = this.canScrollY() ? (
<Scrollbar
realSize={this.state.realHeight}
containerSize={this.state.containerHeight}
position={-this.state.topPosition}
onMove={this.handleMove.bind(this)}
type="vertical"/>
) : null;
var scrollbarX = ...
return (
<div onWheel={this.handleWheel.bind(this)}>
<div className="content" style={style} >
{this.props.children}
</div>
{scrollbarY}
{scrollbarX}
</div>
);
this.state = {
position: props.position * (props.containerSize / props.realSize),
scrollSize: props.containerSize * props.containerSize / props.realSize,
isDragging: false,
isActive: false,
lastClientPosition: 0
}
Ok, this all works so far good before we land on...again, mobile devices
The primary difference of scroll between desktop and mobile devices are the Respond/Event System
Scrolling on a touch device where respond system is primarily driven by 3 events:
Translate the physical algorithm to make touch scrolling feel intuitive
But be aware of that: any DOM layout change will break your perfect scroll!