Skip to content

Commit

Permalink
v3.3.0
Browse files Browse the repository at this point in the history
  • Loading branch information
zengabor committed Nov 20, 2016
1 parent f960845 commit fc3075b
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 26 deletions.
24 changes: 17 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@

Smooth animated scrolling. Move elements into view, or scroll to any vertical position.

1.1 kilobyte of vanilla JavaScript. No dependencies.
1.2 kilobyte of vanilla JavaScript. No dependencies.



## About
Expand All @@ -21,15 +22,17 @@ Zenscroll is a vanilla JavaScript module that enables animated vertical scrollin

Features:

- Smooth animated scrolling, using the browser’s built-in smooth-behavior if it’s enabled.
- Smooth animated scrolling.
- Automatic smooth-scolling on links within the same page.
- Works even if the Back and Forward buttons are used (on compatible browsers).
- 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 and center it on the screen.
- Customize the duration of the individual scroll operations.
- If you provide a callback function it will be executed when the scrolling is done.
- Specify the spacing between the element and the edge of the screen (e.g., for fixed navigation bars and footers).
- Just 1.1 kilobyte minimized & gzipped.
- Uses the browser’s built-in smooth-behavior if it’s enabled.
- Just 1.2 kilobyte minimized & gzipped.
- No dependencies.

Full support tested and works under:
Expand All @@ -52,6 +55,7 @@ Limited support (programmatic animated scroll in document) tested and works unde
- Internet Explorer 6+
- iOS Safari 3+


## Getting Started

### Installing Zenscroll
Expand All @@ -78,7 +82,7 @@ If you want to leverage the native smooth-scrolling by the browser (currently av
body, .smooth-container { scroll-behavior: smooth }
````

In this case Zenscroll will use the browser’s built-in support for all scroll functions. However, note that if you use the native smooth-scrolling then you loose the finer control options that Zenscroll offers: the speed of the animation, and the edge offset for links within the page. Only set this CSS property on the `body` or on the elements if you don’t need this level of control.
If this is set and the browser supports it, Zenscroll will use the browser’s built-in support for smooth-scrolling. However, note that if you use the native smooth-scrolling then you loose the finer control options that Zenscroll offers: the speed settings of the animation, and the edge offset for links within the page. 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

Expand All @@ -93,21 +97,24 @@ If you want to use Zenscroll programmatically but you don’t need the automatic

(I consider this a rare scenario that’s why I keep the default behavior of installing the event handler.)


## How to use


### 1. Smooth scroll within your page

If Zenscroll is included in your page it will automatically animate the scrolling to anchors on the same page.
If Zenscroll is included in your page it will automatically animate the scrolling to anchors on the same page.

However, automatic smooth scrolling within the same page is not enabled in these two cases:

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)). In this case the browser is already smooth-scrolling within the same page.

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">`.

The scroll is also animated when the Back and Forward buttons are used. (Note that it remembers the vertical scroll position but it doesn’t calculate changes caused by browser window resizing or collapsing/expanding elements, etc.) This functionality requires browser support for `history.scrollRestoration` which is available in Chrome 46+ and Firefox 46+. WebKit already has a [ticket](https://bugs.webkit.org/show_bug.cgi?id=147782) for it, in the meantime you can use a polyfill for Safari, like [scroll-restoration-polyfill](https://github.com/bfred-it/scroll-restoration-polyfill).

Automatic smooth-scrolling works also 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.
Automatic smooth-scrolling works also with content you dynamically load via AJAX, as Zenscroll uses a generic click handler. Since the automatic smooth-scrolling is implemented a progressive enhancement, internal links work in older browsers as well.


### 2. Scroll to the top of an element
Expand Down Expand Up @@ -223,7 +230,7 @@ myScroller.intoView(target)

You can provide a callback function to all four scroll functions, which is executed when the scroll operation is finished. For example, you change some UI elements but first you want to make sure that the relevant elements are visible.

If you look at the code examples above under the previous point, [7. Scroll inside a scrollable DIV](#7.scrollinsideascrollablediv) they are actually implemented like this:
If you look at the code examples above under the previous point, [Scroll inside a scrollable DIV](#7.scrollinsideascrollablediv) they are actually implemented like this:

````js
// Last line of example 1:
Expand Down Expand Up @@ -292,12 +299,15 @@ To stop the current scrolling:
zenscroll.stop()
````


## License

[Public Domain](http://unlicense.org). You can do with it whatever you want and I am not responsible for anything.



## Other projects by me:

- [Zenfonts](https://github.com/zengabor/zenfonts), a tiny JavaScript helper for @font-face web font loading.
- [Zenvite.com](http://zenvite.com/): Create invitation pages & get everybody on the same page.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "zenscroll",
"version": "3.2.3",
"version": "3.3.0",
"description": "A module to smooth-scroll web pages and containers (DIVs)",
"main": "zenscroll.js",
"files": ["zenscroll.js", "zenscroll-min.js"],
Expand Down
2 changes: 1 addition & 1 deletion zenscroll-min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

50 changes: 33 additions & 17 deletions zenscroll.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Zenscroll 3.2.3
* Zenscroll 3.3.0
* https://github.com/zengabor/zenscroll/
*
* Copyright 2015–2016 Gabor Lenard
Expand Down Expand Up @@ -46,6 +46,12 @@
}
}(this, function () {
"use strict"

// Detect if the browser already supports native smooth scrolling (e.g., Firefox 36+ and Chrome 49+) and it is enabled:
var isNativeSmoothScrollEnabledOn = function (elem) {
return ("getComputedStyle" in window) &&
window.getComputedStyle(elem)["scroll-behavior"] === "smooth"
}

// Exit if it’s not a browser environment:
if (typeof window === "undefined" || !("document" in window)) {
Expand All @@ -66,12 +72,6 @@
}
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 ("getComputedStyle" in window) &&
window.getComputedStyle(scrollContainer ? scrollContainer : document.body)["scroll-behavior"] === "smooth"
}

var getScrollTop = function () {
if (scrollContainer) {
return scrollContainer.scrollTop
Expand Down Expand Up @@ -111,10 +111,11 @@
* @param {duration} Optionally the duration of the scroll operation.
* If 0 or not provided it is automatically calculated based on the
* distance and the default duration.
* @param {onDone} Callback function to be invoken once the scroll finishes.
*/
var scrollToY = function (endY, duration, onDone) {
stopScroll()
if (nativeSmoothScrollEnabled()) {
if (isNativeSmoothScrollEnabledOn(scrollContainer ? scrollContainer : document.body)) {
(scrollContainer || window).scrollTo(0, endY)
if (onDone) {
onDone()
Expand Down Expand Up @@ -152,9 +153,13 @@
* @param {elem} The element.
* @param {duration} Optionally the duration of the scroll operation.
* A value of 0 is ignored.
* @param {onDone} Callback function to be invoken once the scroll finishes.
* @returns {endY} The new vertical scoll position that will be valid once the scroll finishes.
*/
var scrollToElem = function (elem, duration, onDone) {
scrollToY(getRelativeTopOf(elem) - edgeOffset, duration, onDone)
var endY = getRelativeTopOf(elem) - edgeOffset
scrollToY(endY, duration, onDone)
return endY
}

/**
Expand All @@ -163,6 +168,7 @@
* @param {elem} The element.
* @param {duration} Optionally the duration of the scroll operation.
* A value of 0 is ignored.
* @param {onDone} Callback function to be invoken once the scroll finishes.
*/
var scrollIntoView = function (elem, duration, onDone) {
var elemHeight = elem.getBoundingClientRect().height
Expand All @@ -189,6 +195,7 @@
* @param {duration} Optionally the duration of the scroll operation.
* @param {offset} Optionally the offset of the top of the element from the center of the screen.
* A value of 0 is ignored.
* @param {onDone} Callback function to be invoken once the scroll finishes.
*/
var scrollToCenterOf = function (elem, duration, offset, onDone) {
scrollToY(
Expand Down Expand Up @@ -224,7 +231,8 @@
intoView: scrollIntoView,
center: scrollToCenterOf,
stop: stopScroll,
moving: function () { return !!scrollTimeoutId }
moving: function () { return !!scrollTimeoutId },
getY: getScrollTop
}

}
Expand All @@ -233,14 +241,23 @@
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) {
if ("addEventListener" in window && !(isNativeSmoothScrollEnabledOn(document.body) || window.noZensmooth)) {
if ("scrollRestoration" in history) {
history.scrollRestoration = "manual"
window.addEventListener("popstate", function (event) {
if (event.state && "scrollY" in event.state) {
defaultScroller.toY(event.state.scrollY)
}
}, false)
}
var replaceUrl = function (hash, newY) {
try {
history.replaceState({}, "", window.location.href.split("#")[0] + hash)
history.replaceState({scrollY:defaultScroller.getY()}, "") // remember the scroll position before scrolling
history.pushState({scrollY:newY}, "", window.location.href.split("#")[0] + hash) // remember the new scroll position (which will be after scrolling)
} 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") {
Expand All @@ -255,14 +272,13 @@
if (href === "#") {
event.preventDefault()
defaultScroller.toY(0)
replaceUrl("")
replaceUrl("", 0)
} else {
var targetId = anchor.hash.substring(1)
var targetElem = document.getElementById(targetId)
if (targetElem) {
event.preventDefault()
defaultScroller.to(targetElem)
replaceUrl("#" + targetId)
replaceUrl("#" + targetId, defaultScroller.to(targetElem))
}
}
}
Expand Down

0 comments on commit fc3075b

Please sign in to comment.