Comparing version 2.1.0 to 3.0.0
{ | ||
"name": "zenscroll", | ||
"version": "2.1.0", | ||
"version": "3.0.0", | ||
"description": "A module to smooth-scroll web pages and DIVs", | ||
@@ -5,0 +5,0 @@ "main": "zenscroll.js", |
@@ -11,8 +11,7 @@ <p align="center"> | ||
# One JavaScript to Smooth-Scroll Them All | ||
# One JavaScript to Smooth-Scroll Them All | ||
Smooth animated scrolling. No more abrupt jumps. | ||
Move elements into view, to the center, or scroll to any vertical position. | ||
Smooth animated scrolling. Move elements into view, or scroll to any vertical position. | ||
*875 bytes of pure JavaScript. No dependencies.* | ||
1 kilobyte of pure JavaScript. No dependencies. | ||
@@ -26,9 +25,9 @@ | ||
- Animated scrolling to anchors on the same page. | ||
- Animated scrolling to anchors on the same page (unless the browser natively supports it and it’s enabled). | ||
- Scroll to the top of a specific element. | ||
- Scrolling an element into view, making sure both top & bottom are visible, if possible. | ||
- Scroll to an element while centering it on the screen. | ||
- Customize the duration. | ||
- Specify the spacing between the element and the edge of the screen (required for fixed navigation bars and footers). | ||
- Only 875 bytes minimized & gzipped. | ||
- Scroll to an element and center it on the screen. | ||
- Customize the duration of the individual scroll operations. | ||
- Specify the spacing between the element and the edge of the screen (e.g., for fixed navigation bars and footers). | ||
- Just 1 kilobyte minimized & gzipped. | ||
- No dependencies. | ||
@@ -56,4 +55,6 @@ | ||
## Install | ||
## Getting Started | ||
### Installing Zenscroll | ||
[Download Zenscroll](https://github.com/zengabor/zenscroll/archive/latest.zip) and include it into your page. A good place is at the very bottom, just before the closing `</body>` tag. For example: | ||
@@ -73,7 +74,21 @@ | ||
If you want to use Zenscroll programmatically but you don’t need the automatic smoothing on local links then set `window.noZensmooth` to a non-falsy value. In this case the event handler for automatic smoothing is not installed but you can still use everything, like `zenscroll.intoView()`, etc. For example: | ||
### Enabling native smooth-scrolling in the browser | ||
If you want to leverage the native smooth-scrolling by the browser (currently available in Firefox 36+ and Chrome 49+) then set the [`scroll-behavior` CSS property](https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-behavior) to `smooth` on the body and on the elements you want to scroll. E.g., | ||
````css | ||
body, .smooth-container { scroll-behavior: smooth } | ||
```` | ||
In this case the browser already does native smooth scrolling which is probably more efficient so Zenscroll uses that automatically. | ||
However, note that if you enable native smooth-scrolling then you loose the finer control options that Zenscroll offers: the speed of the animation, and the edge offset. So only set this CSS property on the `body` or on the elements if you don’t need this level of control. | ||
### Disabling automatic smoothing on local links | ||
If you want to use Zenscroll programmatically but you don’t need the automatic smoothing on local links then set `window.noZensmooth` to a non-falsy value. In this case the event handler for automatic smoothing is not installed but you can still use everything, like `zenscroll.intoView()`, etc. It’s important to set this value before Zenscroll is executed, otherwise the handler will be installed. So make sure that setting the variable comes before the loading of the script. For example: | ||
````html | ||
... | ||
<script>window.noZensmooth = true</script> | ||
<script>window.noZensmooth = true</script> | ||
<script src="zenscroll-min.js"></script> | ||
@@ -84,2 +99,3 @@ </body> | ||
(I consider this a rare scenario that’s why I keep the default behavior of installing the event handler.) | ||
## How to use | ||
@@ -90,9 +106,14 @@ | ||
If Zenscroll is included in your page it will automatically animate the scrolling to anchors on the same page. This works even with content you dynamically load via ajax, as Zenscroll uses a generic click handler. | ||
If Zenscroll is included in your page it will automatically animate the scrolling to anchors on the same page. | ||
Since this is implemented a progressive enhancement, all internal links still work even in very old browsers. Note that internal links are intentionally not added to the history to save the users from having to hit the Back button too many times afterwards. | ||
However, automatic smooth scrolling is not enabled in these two cases: | ||
If you want some links to be excluded from this, then start with the path of the page. E.g., instead of writing `<a href="#about">` write `<a href="/#about">`. | ||
1. If you set `window.noZensmooth` to a non-falsy value (see [above](#disablingautomaticsmoothingonlocallinks)). | ||
2. If the `scroll-behavior` CSS property is set to `smooth` on the `body` (see [above](#enablingnativesmooth-scrollinginthebrowser)). | ||
If you want only some of the links to be excluded from the automatic smoothing then start with the path of the page. E.g., instead of writing `<a href="#about">` use `<a href="/#about">`. | ||
Automatic smooth scrolling works with content you dynamically load via AJAX, as Zenscroll uses a generic click handler. Internal links are intentionally not added to the history to save the users from having to hit the Back button too many times afterwards. Since the automatic smooth-scrolling is implemented a progressive enhancement, all internal links still work even in old browsers. | ||
### 2. Scroll to the top of an element | ||
@@ -152,3 +173,3 @@ | ||
The default duration is 999 which is ~1 second. The duration is automatically reduced for elements that are very close. You can specifically set the duration for each scroll method via an optional second parameter. (Note that a value of zero for duration is ignored.) | ||
The default duration is 999 which is ~1 second. The duration is automatically reduced for elements that are very close. You can specifically set the duration for each scroll function via an optional second parameter. (Note that a value of zero for duration is ignored.) | ||
@@ -172,3 +193,3 @@ Examples: | ||
Anything you can do within the document you can also do inside a scrollable element. You just need to instantiate a new scoller for that element. | ||
Anything you can do within the document you can also do inside a scrollable element. You just need to instantiate a new scoller for that element. It also falls back by default to the native browser smooth-scrolling if available (which can be overridden via `setup()`). | ||
@@ -189,19 +210,19 @@ Example: | ||
<script> | ||
var c = document.getElementById("container") | ||
var defaultDuration = 500 | ||
var edgeOffset = 4 | ||
var cScroll = new Zenscroll(c, defaultDuration, edgeOffset) | ||
var myDiv = document.getElementById("container") | ||
var myScroller = zenscroll.createScroller(myDiv, defaultDuration, edgeOffset) | ||
var target = document.getElementById("item4") | ||
cScroll.center(target) | ||
myScroller.center(target) | ||
</script> | ||
```` | ||
Obviously you can use all other scroll methods and parameters with the scrollable container. Two more examples: | ||
Obviously you can use all other scroll functions and parameters with the scrollable container. Two more examples: | ||
````js | ||
cScroll.toY(35) | ||
myScroller.toY(35) | ||
```` | ||
````js | ||
cScroll.intoView(target, 750) | ||
myScroller.intoView(target, 750) | ||
```` | ||
@@ -223,2 +244,8 @@ | ||
You can change custom scrollers similarly: | ||
````js | ||
myScroller.setup(500, 10) | ||
```` | ||
If you don’t want to change a value just omit the parameter or pass `null`. For example, the line below sets the default duration, while leaving other settings unchanged: | ||
@@ -225,0 +252,0 @@ |
@@ -1,1 +0,1 @@ | ||
!function(t,e){"use strict";t.Zenscroll=function n(o,i,r){i=i||999,r&&0===r||(r=9);var c,l=e.documentElement,a=function(){return o?o.scrollTop:t.scrollY||l.scrollTop},u=function(){return o?Math.min(o.offsetHeight,t.innerHeight):t.innerHeight||l.clientHeight},f=function(t){return o?t.offsetTop-o.offsetTop:t.getBoundingClientRect().top+a()-l.offsetTop},s=function M(){clearTimeout(c),c=0},h=function(e,n){s();var r=a(),f=Math.max(e,0)-r;n=n||Math.min(Math.abs(f),i);var h=(new Date).getTime();!function g(){c=setTimeout(function(){var e=Math.min(((new Date).getTime()-h)/n,1),i=Math.max(Math.floor(r+f*(.5>e?2*e*e:e*(4-2*e)-1)),0);o?o.scrollTop=i:t.scrollTo(0,i),1>e&&u()+i<(o||l).scrollHeight?g():setTimeout(s,99)},9)}()},g=function H(t,e){h(f(t)-r,e)},m=function w(t,e){var n=t.getBoundingClientRect().height+2*r,o=u(),i=f(t),c=i+n,l=a();r>i-l||n>o?g(t,e):r>l+o-c&&h(c-o,e)},p=function x(t,e,n){h(Math.max(f(t)-u()/2+(n||t.getBoundingClientRect().height/2),0),e)},v=function B(e){try{history.replaceState({},"",t.location.href.split("#")[0]+(e?"#"+e:""))}catch(n){}},d=function D(e){for(var n=e.target;n&&"A"!==n.tagName;)n=n.parentNode;if(n){var o=n.getAttribute("href")||"";if(0===o.indexOf("#"))if("#"===o)e.preventDefault(),t.zenscroll.toY(0),v("");else{var i=n.hash.substring(1),r=document.getElementById(i);r&&(e.preventDefault(),t.zenscroll.to(r),v(i))}}};!o&&"addEventListener"in t&&!t.noZensmooth&&t.addEventListener("click",d,!1);var T=function E(t,e){t&&(i=t),null!==e&&(r=e)};return{setup:T,to:g,toY:h,intoView:m,center:p,stop:s,moving:function(){return!!c}}},t.zenscroll=new t.Zenscroll}(this,document); | ||
!function(t,e){"function"==typeof define&&define.amd?define([],e()):"object"==typeof module&&module.exports?module.exports=e():t.zenscroll=e()}(this,function(){"use strict";var t=function(t,e,n){e=e||999,n&&0===n||(n=9);var o,i=document.documentElement,r=function(){return"smooth"===(t?t:document.body).style.scrollBehavior},c=function(){return t?t.scrollTop:window.scrollY||i.scrollTop},u=function(){return t?Math.min(t.offsetHeight,window.innerHeight):window.innerHeight||i.clientHeight},f=function(e){return t?e.offsetTop-t.offsetTop:e.getBoundingClientRect().top+c()-i.offsetTop},l=function(){clearTimeout(o),o=0},a=function(n,f){if(l(),r())(t||window).scrollTo(0,n);else{var a=c(),s=Math.max(n,0)-a;f=f||Math.min(Math.abs(s),e);var d=(new Date).getTime();!function h(){o=setTimeout(function(){var e=Math.min(((new Date).getTime()-d)/f,1),n=Math.max(Math.floor(a+s*(.5>e?2*e*e:e*(4-2*e)-1)),0);t?t.scrollTop=n:window.scrollTo(0,n),1>e&&u()+n<(t||i).scrollHeight?h():setTimeout(l,99)},9)}()}},s=function(t,e){a(f(t)-n,e)},d=function(t,e){var o=t.getBoundingClientRect().height+2*n,i=u(),r=f(t),l=r+o,d=c();n>r-d||o>i?s(t,e):n>d+i-l&&a(l-i,e)},h=function(t,e,n){a(Math.max(f(t)-u()/2+(n||t.getBoundingClientRect().height/2),0),e)},m=function(t,o){t&&(e=t),(0===o||o)&&(n=o)};return{setup:m,to:s,toY:a,intoView:d,center:h,stop:l,moving:function(){return!!o}}},e=t();if("addEventListener"in window&&"smooth"!==document.body.style.scrollBehavior&&!window.noZensmooth){var n=function(t){try{history.replaceState({},"",window.location.href.split("#")[0]+t)}catch(e){}};window.addEventListener("click",function(t){for(var o=t.target;o&&"A"!==o.tagName;)o=o.parentNode;if(!(!o||1!==t.which||t.shiftKey||t.metaKey||t.ctrlKey||t.altKey)){var i=o.getAttribute("href")||"";if(0===i.indexOf("#"))if("#"===i)t.preventDefault(),e.toY(0),n("");else{var r=o.hash.substring(1),c=document.getElementById(r);c&&(t.preventDefault(),e.to(c),n("#"+r))}}},!1)}return{createScroller:t,setup:e.setup,to:e.to,toY:e.toY,intoView:e.intoView,center:e.center,stop:e.stop,moving:e.moving}}); |
180
zenscroll.js
/** | ||
* Zenscroll 2.0.0 | ||
* Zenscroll 3.0.0 | ||
* https://github.com/zengabor/zenscroll/ | ||
@@ -36,11 +36,21 @@ * | ||
/*global define, module */ | ||
(function (win, doc) { | ||
(function (root, zenscroll) { | ||
if (typeof define === "function" && define.amd) { | ||
define([], zenscroll()) | ||
} else if (typeof module === "object" && module.exports) { | ||
module.exports = zenscroll() | ||
} else { | ||
root.zenscroll = zenscroll() | ||
} | ||
}(this, function () { | ||
"use strict" | ||
var createScroller = function (scrollContainer, defaultDuration, edgeOffset) { | ||
win.Zenscroll = function Zenscroll(scrollContainer, defaultDuration, edgeOffset) { | ||
defaultDuration = defaultDuration || 999 //ms | ||
if (!edgeOffset || edgeOffset !== 0) { | ||
// When scrolling this amount of distance is kept from the edges of the scrollContainer | ||
// When scrolling, this amount of distance is kept from the edges of the scrollContainer: | ||
edgeOffset = 9 //px | ||
@@ -50,6 +60,11 @@ } | ||
var scrollTimeoutId | ||
var docElem = doc.documentElement | ||
var docElem = document.documentElement | ||
// Detect if the browser already supports native smooth scrolling (e.g., Firefox 36+ and Chrome 49+) and it is enabled: | ||
var nativeSmoothScrollEnabled = function () { | ||
return (scrollContainer ? scrollContainer : document.body).style.scrollBehavior === "smooth" | ||
} | ||
var getScrollTop = function () { | ||
return scrollContainer ? scrollContainer.scrollTop : win.scrollY || docElem.scrollTop | ||
return scrollContainer ? scrollContainer.scrollTop : (window.scrollY || docElem.scrollTop) | ||
} | ||
@@ -59,4 +74,4 @@ | ||
return scrollContainer ? | ||
Math.min(scrollContainer.offsetHeight, win.innerHeight) : | ||
win.innerHeight || docElem.clientHeight | ||
Math.min(scrollContainer.offsetHeight, window.innerHeight) : | ||
window.innerHeight || docElem.clientHeight | ||
} | ||
@@ -75,3 +90,3 @@ | ||
*/ | ||
var stopScroll = function stopScroll() { | ||
var stopScroll = function () { | ||
clearTimeout(scrollTimeoutId) | ||
@@ -91,22 +106,26 @@ scrollTimeoutId = 0 | ||
stopScroll() | ||
var startY = getScrollTop() | ||
var distance = Math.max(endY,0) - startY | ||
duration = duration || Math.min(Math.abs(distance), defaultDuration) | ||
var startTime = new Date().getTime(); | ||
(function loopScroll() { | ||
scrollTimeoutId = setTimeout(function () { | ||
var p = Math.min((new Date().getTime() - startTime) / duration, 1) // percentage | ||
var y = Math.max(Math.floor(startY + distance*(p < 0.5 ? 2*p*p : p*(4 - p*2)-1)), 0) | ||
if (scrollContainer) { | ||
scrollContainer.scrollTop = y | ||
} else { | ||
win.scrollTo(0, y) | ||
} | ||
if (p < 1 && (getViewHeight() + y) < (scrollContainer || docElem).scrollHeight) { | ||
loopScroll() | ||
} else { | ||
setTimeout(stopScroll, 99) // with cooldown time | ||
} | ||
}, 9) | ||
})() | ||
if (nativeSmoothScrollEnabled()) { | ||
(scrollContainer || window).scrollTo(0, endY) | ||
} else { | ||
var startY = getScrollTop() | ||
var distance = Math.max(endY,0) - startY | ||
duration = duration || Math.min(Math.abs(distance), defaultDuration) | ||
var startTime = new Date().getTime(); | ||
(function loopScroll() { | ||
scrollTimeoutId = setTimeout(function () { | ||
var p = Math.min((new Date().getTime() - startTime) / duration, 1) // percentage | ||
var y = Math.max(Math.floor(startY + distance*(p < 0.5 ? 2*p*p : p*(4 - p*2)-1)), 0) | ||
if (scrollContainer) { | ||
scrollContainer.scrollTop = y | ||
} else { | ||
window.scrollTo(0, y) | ||
} | ||
if (p < 1 && (getViewHeight() + y) < (scrollContainer || docElem).scrollHeight) { | ||
loopScroll() | ||
} else { | ||
setTimeout(stopScroll, 99) // with cooldown time | ||
} | ||
}, 9) | ||
})() | ||
} | ||
} | ||
@@ -121,3 +140,3 @@ | ||
*/ | ||
var scrollToElem = function scrollToElem(elem, duration) { | ||
var scrollToElem = function (elem, duration) { | ||
scrollToY(getRelativeTopOf(elem) - edgeOffset, duration) | ||
@@ -133,3 +152,3 @@ } | ||
*/ | ||
var scrollIntoView = function scrollIntoView(elem, duration) { | ||
var scrollIntoView = function (elem, duration) { | ||
var elemScrollHeight = elem.getBoundingClientRect().height + 2*edgeOffset | ||
@@ -157,3 +176,3 @@ var vHeight = getViewHeight() | ||
*/ | ||
var scrollToCenterOf = function scrollToCenterOf(elem, duration, offset) { | ||
var scrollToCenterOf = function (elem, duration, offset) { | ||
scrollToY( | ||
@@ -168,39 +187,2 @@ Math.max( | ||
var replaceUrl = function replaceUrl(hash) { | ||
try { | ||
history.replaceState({}, "", win.location.href.split("#")[0] + (hash ? "#" + hash : "")) | ||
} catch (e) { | ||
// To avoid the Security exception in Chrome when the page was opened via the file protocol, e.g., file://index.html | ||
} | ||
} | ||
var internalLinkHandler = function internalLinkHandler(event) { | ||
var anchor = event.target | ||
while (anchor && anchor.tagName !== "A") { | ||
anchor = anchor.parentNode | ||
} | ||
if (anchor) { | ||
var href = anchor.getAttribute("href") || "" | ||
if (href.indexOf("#") === 0) { | ||
if (href === "#") { | ||
event.preventDefault() | ||
win.zenscroll.toY(0) | ||
replaceUrl("") | ||
} else { | ||
var targetId = anchor.hash.substring(1) | ||
var targetElem = document.getElementById(targetId) | ||
if (targetElem) { | ||
event.preventDefault() | ||
win.zenscroll.to(targetElem) | ||
replaceUrl(targetId) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
// create listeners for the documentElement only & exclude IE8- | ||
if (!scrollContainer && "addEventListener" in win && !win.noZensmooth) { | ||
win.addEventListener("click", internalLinkHandler, false) | ||
} | ||
/** | ||
@@ -213,7 +195,7 @@ * Changes default settings for this scroller. | ||
*/ | ||
var setup = function setup(newDefaultDuration, newEdgeOffset) { | ||
var setup = function (newDefaultDuration, newEdgeOffset) { | ||
if (newDefaultDuration) { | ||
defaultDuration = newDefaultDuration | ||
} | ||
if (newEdgeOffset !== null) { | ||
if (newEdgeOffset === 0 || newEdgeOffset) { | ||
edgeOffset = newEdgeOffset | ||
@@ -235,8 +217,56 @@ } | ||
// Create a scroller for the browser window, omitting parameters: | ||
var defaultScroller = createScroller() | ||
// Create listeners for the documentElement only & exclude IE8- | ||
if ("addEventListener" in window && document.body.style.scrollBehavior !== "smooth" && !window.noZensmooth) { | ||
var replaceUrl = function (hash) { | ||
try { | ||
history.replaceState({}, "", window.location.href.split("#")[0] + hash) | ||
} catch (e) { | ||
// To avoid the Security exception in Chrome when the page was opened via the file protocol, e.g., file://index.html | ||
} | ||
} | ||
window.addEventListener("click", function (event) { | ||
var anchor = event.target | ||
while (anchor && anchor.tagName !== "A") { | ||
anchor = anchor.parentNode | ||
} | ||
if (!anchor || event.which !== 1 || event.shiftKey || event.metaKey || event.ctrlKey || event.altKey) { | ||
return | ||
} | ||
var href = anchor.getAttribute("href") || "" | ||
if (href.indexOf("#") === 0) { | ||
if (href === "#") { | ||
event.preventDefault() // Prevent the browser from handling the activation of the link | ||
defaultScroller.toY(0) | ||
replaceUrl("") | ||
} else { | ||
var targetId = anchor.hash.substring(1) | ||
var targetElem = document.getElementById(targetId) | ||
if (targetElem) { | ||
event.preventDefault() // Prevent the browser from handling the activation of the link | ||
defaultScroller.to(targetElem) | ||
replaceUrl("#" + targetId) | ||
} | ||
} | ||
} | ||
}, false) | ||
} | ||
win.zenscroll = new win.Zenscroll() | ||
return { | ||
// Expose the "constructor" that can create a new scroller: | ||
createScroller: createScroller, | ||
// Surface the methods of the default scroller: | ||
setup: defaultScroller.setup, | ||
to: defaultScroller.to, | ||
toY: defaultScroller.toY, | ||
intoView: defaultScroller.intoView, | ||
center: defaultScroller.center, | ||
stop: defaultScroller.stop, | ||
moving: defaultScroller.moving | ||
} | ||
})); | ||
})(this, document); | ||
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
22212
236
277