Last active
April 9, 2022 00:06
-
-
Save madrobby/8507960 to your computer and use it in GitHub Desktop.
scrolltotop, a Zepto plugin to scroll things to the top (and any other vertical scroll position)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Usage: $(element).scrollToTop([position]) | |
;(function($){ | |
// only allow one scroll to top operation to be in progress at a time, | |
// which is probably what you want | |
var scrollToTopInProgress = false | |
$.fn.scrollToTop = function(position){ | |
var $this = this, | |
targetY = position || 0, | |
initialY = $this.scrollTop(), | |
lastY = initialY, | |
delta = targetY - initialY, | |
// duration in ms, make it a bit shorter for short distances | |
// this is not scientific and you might want to adjust this for | |
// your preferences | |
speed = Math.min(750, Math.min(1500, Math.abs(initialY-targetY))), | |
// temp variables (t will be a position between 0 and 1, y is the calculated scrollTop) | |
start, t, y, | |
// use requestAnimationFrame or polyfill | |
frame = window.requestAnimationFrame || | |
window.webkitRequestAnimationFrame || | |
window.mozRequestAnimationFrame || | |
function(callback){ setTimeout(callback,15) }, | |
cancelScroll = function(){ abort() } | |
// abort if already in progress or nothing to scroll | |
if (scrollToTopInProgress) return | |
if (delta == 0) return | |
// quint ease-in-out smoothing, from | |
// https://github.com/madrobby/scripty2/blob/master/src/effects/transitions/penner.js#L127-L136 | |
function smooth(pos){ | |
if ((pos/=0.5) < 1) return 0.5*Math.pow(pos,5) | |
return 0.5 * (Math.pow((pos-2),5) + 2) | |
} | |
function abort(){ | |
$this.off('touchstart', cancelScroll) | |
scrollToTopInProgress = false | |
} | |
// when there's a touch detected while scrolling is in progress, abort | |
// the scrolling (emulates native scrolling behavior) | |
$this.on('touchstart', cancelScroll) | |
scrollToTopInProgress = true | |
// start rendering away! note the function given to frame | |
// is named "render" so we can reference it again further down | |
frame(function render(now){ | |
if (!scrollToTopInProgress) return | |
if (!start) start = now | |
// calculate t, position of animation in [0..1] | |
t = Math.min(1, Math.max((now - start)/speed, 0)) | |
// calculate the new scrollTop position (don't forget to smooth) | |
y = Math.round(initialY + delta * smooth(t)) | |
// bracket scrollTop so we're never over-scrolling | |
if (delta > 0 && y > targetY) y = targetY | |
if (delta < 0 && y < targetY) y = targetY | |
// only actually set scrollTop if there was a change fromt he last frame | |
if (lastY != y) $this.scrollTop(y) | |
lastY = y | |
// if we're not done yet, queue up an other frame to render, | |
// or clean up | |
if (y !== targetY) frame(render) | |
else abort() | |
}) | |
} | |
})(Zepto) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;(function($){ | |
var scrollToTopInProgress = false | |
$.fn.scrollToTop = function(position){ | |
var $this = this, | |
targetY = position || 0, | |
initialY = $this.scrollTop(), | |
lastY = initialY, | |
delta = targetY - initialY, | |
speed = Math.min(750, Math.min(1500, Math.abs(initialY-targetY))), | |
start, t, y, frame = window.requestAnimationFrame || | |
window.webkitRequestAnimationFrame || | |
window.mozRequestAnimationFrame || | |
function(callback){ setTimeout(callback,15) }, | |
cancelScroll = function(){ abort() } | |
if (scrollToTopInProgress) return | |
if (delta == 0) return | |
function smooth(pos){ | |
if ((pos/=0.5) < 1) return 0.5*Math.pow(pos,5) | |
return 0.5 * (Math.pow((pos-2),5) + 2) | |
} | |
function abort(){ | |
$this.off('touchstart', cancelScroll) | |
scrollToTopInProgress = false | |
} | |
$this.on('touchstart', cancelScroll) | |
scrollToTopInProgress = true | |
frame(function render(now){ | |
if (!scrollToTopInProgress) return | |
if (!start) start = now | |
t = Math.min(1, Math.max((now - start)/speed, 0)) | |
y = Math.round(initialY + delta * smooth(t)) | |
if (delta > 0 && y > targetY) y = targetY | |
if (delta < 0 && y < targetY) y = targetY | |
if (lastY != y) $this.scrollTop(y) | |
lastY = y | |
if (y !== targetY) frame(render) | |
else abort() | |
}) | |
} | |
})(Zepto) |
Great Code !!
I wonder if the argument now
become undefined, if setTimeout
will be used.
Anyway, your code inspired me, especially using ease-in-out for page scroll.
Thank you.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Great stuff 👍
What if
targetY
was a parameter (defaults to0
) and the function name wasscrollto
instead? Small modifications that makes it more flexible.