Ruslan_xDD,
http://cubic-bezier.com/#.16,.73,.88,.39
https://github.com/gre/bezier-easing
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta name="robots" content="noindex">
<title> - jsFiddle demo</title>
<style type='text/css'>
html, body {
height: 3000px;
}
#totop {
position: fixed;
bottom: 10%;
right: 10%;
background: red;
width: 50px;
height: 50px;
cursor: pointer;
opacity: 0;
transition: all 0.5s linear;
visibility: hidden;
}
#totop.show {
opacity: 1;
visibility: visible;
}
</style>
<script>
var NEWTON_ITERATIONS = 4,
NEWTON_MIN_SLOPE = .001,
SUBDIVISION_PRECISION = 1E-7,
SUBDIVISION_MAX_ITERATIONS = 10,
kSplineTableSize = 11,
kSampleStepSize = 1 / (kSplineTableSize - 1),
float32ArraySupported = "function" === typeof Float32Array;
function A(a, b) {
return 1 - 3 * b + 3 * a
}
function B(a, b) {
return 3 * b - 6 * a
}
function C(a) {
return 3 * a
}
function calcBezier(a, b, c) {
return ((A(b, c) * a + B(b, c)) * a + C(b)) * a
}
function getSlope(a, b, c) {
return 3 * A(b, c) * a * a + 2 * B(b, c) * a + C(b)
}
function binarySubdivide(a, b, c, d, e) {
var f, g, h = 0;
do g = b + (c - b) / 2, f = calcBezier(g, d, e) - a, 0 < f ? c = g : b = g; while (Math.abs(f) > SUBDIVISION_PRECISION && ++h < SUBDIVISION_MAX_ITERATIONS);
return g
}
function newtonRaphsonIterate(a, b, c, d) {
for (var e = 0; e < NEWTON_ITERATIONS; ++e) {
var f = getSlope(b, c, d);
if (0 === f) break;
var g = calcBezier(b, c, d) - a;
b -= g / f
}
return b
}
function BezierEasing(a, b, c, d) {
if (4 === arguments.length) return new BezierEasing([a, b, c, d]);
if (!(this instanceof BezierEasing)) return new BezierEasing(a);
if (!a || 4 !== a.length) throw Error("BezierEasing: points must contains 4 values");
for (var e = 0; 4 > e; ++e)
if ("number" !== typeof a[e] || isNaN(a[e]) || !isFinite(a[e])) throw Error("BezierEasing: points should be integers.");
if (0 > a[0] || 1 < a[0] || 0 > a[2] || 1 < a[2]) throw Error("BezierEasing x values must be in [0, 1] range.");
this._str = "BezierEasing(" + a + ")";
this._css =
"cubic-bezier(" + a + ")";
this._p = a;
this._mSampleValues = float32ArraySupported ? new Float32Array(kSplineTableSize) : Array(kSplineTableSize);
this._precomputed = !1;
this.get = this.get.bind(this)
}
BezierEasing.prototype = {
get: function(a) {
var b = this._p[0],
c = this._p[1],
d = this._p[2],
e = this._p[3];
this._precomputed || this._precompute();
return b === c && d === e ? a : 0 === a ? 0 : 1 === a ? 1 : calcBezier(this._getTForX(a), c, e)
},
getPoints: function() {
return this._p
},
toString: function() {
return this._str
},
toCSS: function() {
return this._css
},
_precompute: function() {
var a = this._p[0],
b = this._p[1],
c = this._p[2],
d = this._p[3];
this._precomputed = !0;
a === b && c === d || this._calcSampleValues()
},
_calcSampleValues: function() {
for (var a = this._p[0],
b = this._p[2], c = 0; c < kSplineTableSize; ++c) this._mSampleValues[c] = calcBezier(c * kSampleStepSize, a, b)
},
_getTForX: function(a) {
for (var b = this._p[0], c = this._p[2], d = this._mSampleValues, e = 0, f = 1, g = kSplineTableSize - 1; f !== g && d[f] <= a; ++f) e += kSampleStepSize;
--f;
d = e + (a - d[f]) / (d[f + 1] - d[f]) * kSampleStepSize;
f = getSlope(d, b, c);
return f >= NEWTON_MIN_SLOPE ? newtonRaphsonIterate(a, d, b, c) : 0 === f ? d : binarySubdivide(a, e, e + kSampleStepSize, b, c)
}
};
BezierEasing.css = {
ease: BezierEasing.ease = BezierEasing(.25, .1, .25, 1),
linear: BezierEasing.linear = BezierEasing(0, 0, 1, 1),
"ease-in": BezierEasing.easeIn = BezierEasing(.42, 0, 1, 1),
"ease-out": BezierEasing.easeOut = BezierEasing(0, 0, .58, 1),
"ease-in-out": BezierEasing.easeInOut = BezierEasing(.42, 0, .58, 1)
};
</script>
<script>
window.onload = function() {
var toTop = document.getElementById("totop"),
toTopIsVisible = false,
duration = 1000,
play = false;
window.onscroll = function() {
if (window.pageYOffset > document.documentElement.clientHeight != toTopIsVisible) {
toTopIsVisible = !toTopIsVisible;
toTop.classList.toggle("show", toTopIsVisible)
}
};
//var easing = BezierEasing.easeInOut;
var easing = BezierEasing(.42,0,.58,1)
toTop.onclick = function(e) {
if (play) return;
play = true;
var d = performance.now();
var from = window.pageYOffset;
window.requestAnimationFrame(function foo(a) {
var a = (a - d) / duration;
1 < a && (a = 1);
var progress = easing.get(a);
window.scrollTo(0, from - from * progress);
if (a == 1) {
play = false;
alert(performance.now() - d)
} else window.requestAnimationFrame(foo)
});
return false
}
};
</script>
</head>
<body>
<a href="#" id="totop"></a>
</body>
</html>