diff --git a/.gitattributes b/.gitattributes deleted file mode 100755 index b383ed1..0000000 --- a/.gitattributes +++ /dev/null @@ -1,2 +0,0 @@ -index.html linguist-documentation -index.css linguist-documentation \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index e7e7e44..cffd0b9 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,13 +4,23 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.0.0] - 2018-12-08 +### Added + - The methods 'destroy' and 'polyfill' are now exported (CommonJS) or exposed on window.SmoothscrollAnchorPolyfill. The polyfill still runs automatically on load so embedding it is enough, but now you can destroy it if you want (EventListeners are removed) and start it again, later. + - In addition to `window.__forceSmoothscrollAnchorPolyfill__`, you can now pass `{ force: true }` when invoking `polyfill()` to force-enable the package even in browsers with native support +### Changed + - Updated the documentation website to reflect the new API + - Moved the documentation in a separate docs/ folder to clean up the repo + - Small fixes for formatting and typos in the README + ## [1.0.0-beta] - 2018-12-05 ### Changed - The README.md file has been updated to match the API of v1.0.0 - - Fixed 'window is not defined' error in Node environments, important for usage with SSR - BREAKING: Polyfill now only handles smooth scroll if scroll-behavior is set to 'smooth' via <html style="">, documentElement.style.scrollBehavior or a custom font-family (more information will be added to the documentation) ### Added - Tests for smooth scrolling when clicking anchors have been implemented +### Fixed + - Fixed 'window is not defined' error in Node environments, important for usage with SSR ## [0.12.0] - 2018-11-15 ### Added @@ -20,12 +30,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - When navigating to an anchor, the anchor is now focused. - In browsers supporting the optional `preventScroll` argument, the anchor is focused immediately and the focus scroll is prevented by passing this argument. - If the browser doesn't support `preventScroll` (e.g. Internet Explorer), the focus is scheduled to happen 450ms after the smooth scroll started so it does not interfere with the smooth scrolling (which caused flickering). - - ### Changed - The flag to enforce the polyfill (even if the browser has native support) is now called (`window.__forceSmoothscrollAnchorPolyfill__`). The docs have been updated to reflect this. - - ### Fixed - The polyfill now properly handles Shift/Meta keys and allows for opening links in new windows by shift-clicking instead of preventing it with `event.preventDefault()` - The docs website now works in Internet Explorer 9, polyfills for `Element.classList`, `requestAnimationFrame` + an alternative for flexbox layouts have been added diff --git a/README.md b/README.md index e5f68b3..6289e2d 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@

NPM version - Build status + Build status License + Documentation

  @@ -20,14 +21,14 @@ | --------- | --------- | --------- | --------- | --------- | --------- | | IE9+, Edge| native| native*| last 2 versions| last 2 versions| native* -> \* hashchange navigation triggered by forwards/backwards buttons isn't smooth despite native support. [Learn more](https://jonaskuske.github.io/smoothscroll-anchor-polyfill#hashchange) +> \* hashchange navigation triggered by forwards/backwards buttons isn't smooth despite native support. [Learn more](https://jonaskuske.github.io/smoothscroll-anchor-polyfill#hashchange-blink)   ## Usage ### 1. Set `scroll-behavior: smooth` in CSS -> Has to be set global (on `html`), [check the docs for limitations](https://jonaskuske.github.io/smoothscroll-anchor-polyfill#limitations) +> Has to be set global (on `html`), [check the docs for limitations](https://jonaskuske.github.io/smoothscroll-anchor-polyfill#global-only) Because CSS properties unknown to a browser can't efficiently be parsed from JavaScript, using normal stylesheets is not enough unfortunately. To specify the property in a way the polyfill can read it, you have two options: #### 1a. Using inline styles @@ -57,7 +58,7 @@ Alternatively, you can specify the property as the name of a custom font family. ### 2. Install the polyfill Because this polyfill only wires up anchor links to use the browser's native `window.scroll()` and `element.scrollIntoView()` methods, you'll need to load a polyfill providing smooth scroll to these methods in addition to the steps outlined below. -> [smoothscroll-polyfill](http://iamdustan.com/smoothscroll/) works, but you can just as well use another one or write your own implementation. [Learn More](https://jonaskuske.github.io/smoothscroll-anchor-polyfill#requirements) +> [smoothscroll-polyfill](http://iamdustan.com/smoothscroll/) works, but you can just as well use another one or write your own implementation. [Learn More](https://jonaskuske.github.io/smoothscroll-anchor-polyfill#usage) #### 2a. From a CDN ```html @@ -77,9 +78,7 @@ import 'smoothscroll-anchor-polyfill'; ## Full Documentation & Demo -> ⚠ The documentation is not up-to-date as of now, it will be updated when this packages leaves the beta phase. - -The full documentation with advanced installation instructions, known limitations, features like enabling and disabling the smooth scroll and more can be found at +The full documentation with advanced installation instructions, limitations, features like enabling and disabling the smooth scrolling and more can be found at [**jonaskuske.github.io/smoothscroll-anchor-polyfill**](https://jonaskuske.github.io/smoothscroll-anchor-polyfill). The documentation site itself is built as a smooth scrolling one-page design, utilizing this polyfill. diff --git a/favicon.ico b/docs/favicon.ico similarity index 100% rename from favicon.ico rename to docs/favicon.ico diff --git a/index.css b/docs/index.css similarity index 60% rename from index.css rename to docs/index.css index 248409d..62223d1 100755 --- a/index.css +++ b/docs/index.css @@ -1,9 +1,3 @@ -html { - scroll-behavior: smooth; - /* Additionally specified in custom font-family so polyfill can parse it */ - font-family: 'scroll-behavior:smooth'; -} - body { margin: 0; font-family: 'Roboto', 'Helvetica Neue', 'Helvetica', 'Arial', 'Segoe UI Emoji', 'Apple Color Emoji', 'Noto Color Emoji', sans-serif; @@ -63,7 +57,43 @@ header, section, .fullscreen { } section, .fullscreen { - padding-top: 11rem; + padding-top: 5rem; +} + +.smooth-scroll { + scroll-behavior: smooth; + /* Additionally specified in custom font-family so polyfill can parse it */ + font-family: 'scroll-behavior:smooth'; +} + +.fullscreen h1 { + margin-top: 13rem; +} + +.scroll-btn { + margin-top: 7rem; +} + +@media screen and (min-height: 660px) { + .fullscreen h1 { + margin-top: 18rem; + } + .scroll-btn { + margin-top: 12rem; + } +} + +@media screen and (min-height: 900px) { + .fullscreen h1 { + margin-top: 30rem; + } + .scroll-btn { + margin-top: 24rem; + } +} + +html:not(.smooth-scroll) .scroll-btn { + font-weight: lighter; } .max-width { @@ -100,19 +130,19 @@ html:not(.flex-center) .fullscreen>div { margin-bottom: 0; } -#start { +section:nth-child(2) { background: #faf7fc; } -#usage { +section:nth-child(3) { background: #f6effa; } -#docs { +section:nth-child(4) { background: #f1e7f7; } -#legal, footer>div { +section:nth-child(5), footer>div { background: #eddff5; } @@ -170,26 +200,59 @@ footer>div.row p { } } -h1[id], h2[id], h3[id], h4[id], h1[data-to], h2[data-to], h3[data-to], h4[data-to] { +h1[id] span, h2[id] span, h3[id] span, h4[id] span { position: relative; transition: padding 200ms ease-out; cursor: pointer; } -h1[id]::before, h2[id]::before, h3[id]::before, h4[id]::before, h1[data-to]::before, h2[data-to]::before, h3[data-to]::before, h4[data-to]::before { +h1[id] span::before, h2[id] span::before, h3[id] span::before, h4[id] span::before { content: "#"; position: absolute; left: 0; - top: 50%; - transform: translate(-50%, -50%); + bottom: 0%; + transform: translateX(-50%); opacity: 0; transition: opacity 0.3s ease-out; } -h1[id]:hover, h2[id]:hover, h3[id]:hover, h4[id]:hover, h1[data-to]:hover, h2[data-to]:hover, h3[data-to]:hover, h4[data-to]:hover { +h1[id] span:hover, h2[id] span:hover, h3[id] span:hover, h4[id] span:hover { padding-left: 2rem; } -h1[id]:hover::before, h2[id]:hover::before, h3[id]:hover::before, h4[id]:hover::before, h1[data-to]:hover::before, h2[data-to]:hover::before, h3[data-to]:hover::before, h4[data-to]:hover::before { +h1[id] span:hover::before, h2[id] span:hover::before, h3[id] span:hover::before, h4[id] span:hover::before { opacity: 0.5; +} + +.allow-overflow { + overflow: auto; +} + +/* Add invisible padding to top of targetable elements, +so they're not hidden under the header when scrolled to top */ + +[id] { + padding-top: 90px; + margin-top: -90px; +} + +@media screen and (max-width: 785px) { + [id] { + padding-top: 110px; + margin-top: -110px; + } +} + +@media screen and (max-width: 545px) { + [id] { + padding-top: 145px; + margin-top: -145px; + } +} + +@media screen and (max-width: 425px) { + [id] { + padding-top: 175px; + margin-top: -175px; + } } \ No newline at end of file diff --git a/index.html b/docs/index.html similarity index 56% rename from index.html rename to docs/index.html index b884fb9..e0bea64 100755 --- a/index.html +++ b/docs/index.html @@ -1,5 +1,5 @@ - + @@ -13,10 +13,10 @@ // Element.classList polyfill ; (function () { function a(e) { this.element = e } var b = function (e) { return e.replace(/^\s+|\s+$/g, '') }, c = function (e) { return new RegExp('(^|\\s+)' + e + '(\\s+|$)') }, d = function (e, f, g) { for (var h = 0; h < e.length; h++)f.call(g, e[h]) }; a.prototype = { add: function add() { d(arguments, function (e) { this.contains(e) || (this.element.className = b(this.element.className + ' ' + e)) }, this) }, remove: function remove() { d(arguments, function (e) { this.element.className = b(this.element.className.replace(c(e), ' ')) }, this) }, toggle: function toggle(e) { return this.contains(e) ? (this.remove(e), !1) : (this.add(e), !0) }, contains: function contains(e) { return c(e).test(this.element.className) }, item: function item(e) { return this.element.className.split(/\s+/)[e] || null }, replace: function replace(e, f) { this.remove(e), this.add(f) } }, 'classList' in Element.prototype || Object.defineProperty(Element.prototype, 'classList', { get: function get() { return new a(this) } }), window.DOMTokenList && !DOMTokenList.prototype.replace && (DOMTokenList.prototype.replace = a.prototype.replace) })(); - - + + - + @@ -46,21 +46,24 @@
-

smoothscroll-anchor-polyfill

+

smoothscroll-anchor-polyfill

⚓ Apply smooth scroll to anchor links to replicate CSS scroll-behavior

- GitHub +
GitHub
+
-
-

Start

-

The Scroll Behavior specification allows for native smooth +

+

Start

+

The Scroll + Behavior specification allows for + native smooth scrolling in browsers – both by using JavaScript scroll APIs like window.scrollTo and - element.scrollIntoView or by simply setting the + Element.scrollIntoView or by simply setting the property scroll-behavior to smooth in CSS, which will then make any scrolling smooth by default. This includes @@ -85,59 +88,102 @@

Start

-
-

Usage

-

Requirements

-

Since this script uses the JavaScript scroll APIs and relies on +

+

Usage

+

⚠ Since this script uses the JavaScript scroll APIs and relies on their smooth scroll functionality to operate, you'll need a polyfill for the Scroll Behavior spec in order for this script to make a difference. smoothscroll-polyfill is used as example throughout this site, but you may just as well use another polyfill – or write your own implementation.

-

⚠ Furthermore, this script assumes that scroll-behavior - is set globally to smooth in your CSS. If you don't do that, - scroll behavior will differ between browsers with and without - native support for Scroll Behavior. Set it as follows:

-
<style>
-html {
-  scroll-behavior: smooth;
-}
-</style>
+        

1. Setting scroll-behavior in CSS

+

Because browsers don't parse CSS properties they don't recognize. + For this reason, reading the scroll-behavior property + from your regular stylesheets is unfortunately not possible (without + a performance hit). Instead, specify scroll-behavior + using one of these options:

+

Option 1: Using the inline style attribute

+

Simply define scroll-behaviour as an inline style on + the html element:

+
<html style="scroll-behavior: smooth;">
+...
+</html>
 
+

This way, the polyfill can read the + property using getAttribute('style') even if the browser + doesn't parse it.

+ +

Option 2: Using font-family as + workaround

+

Alternatively, you can specify the property as the name of a custom + font family: +

<style>
+  html {
+    /* Normal CSS properties for browsers with native support */
+    scroll-behavior: smooth;
+
+    /* Additionally defined as the name of a font, so the polyfill can read it */
+    font-family: "scroll-behavior: smooth", sans-serif;
+  }
+<style>
+ Your actual fonts will still work the way they should – plus, you can + simply declare actual fonts on body { } and use font + styles on html { } exclusively for the means of this + polyfill, which is prefered. Unlike inline styles, this allows you to + use normal CSS features like media queries or classes. The following + only enables smooth scroll on desktop devices, for example:

+
<style>
+  html {
+    scroll-behavior: auto;
+    font-family: "scroll-behavior: auto";
+  }
+  @media screen and (min-width: 1150px) {
+    html {
+      scroll-behavior: smooth;
+      font-family: "scroll-behavior: smooth";
+    }
+  }
+<style>
+

💡 Redeclaring your scroll-behavior properties as font + names can be automated using a PostCSS + plugin, so you can write regular CSS and don't have to + bother with font-families. It just works™

-

Basic usage

+

2. Installing the polyfill

+

Option 1: Using <script>

Simply drop in <script> tags linking to the - polyfills and and you're good to go.

+ polyfills and you're good to go.

-
<!-- A polyfill to enable smoothscroll for the JavaScript APIs -->
-<script src="https://unpkg.com/smoothscroll-polyfill"></script>
+        
<!-- Any polyfill to enable smoothscroll for the JavaScript APIs -->
+<script src="https://unpkg.com/smoothscroll-polyfill/dist/smoothscroll.min.js"></script>
 
 <!-- This package, to apply the smoothscroll to anchor links -->
 <script src="https://unpkg.com/smoothscroll-anchor-polyfill"></script>
 
-

With npm

-

Alternatively, if you're using npm, you can - install using - npm install smoothscroll-anchor-polyfill and then use - the polyfill by - requiring/importing it in your JS.

- -
// Import any polyfill to enable smoothscroll for JS APIs
+        

Option 2: With npm

+

Alternatively, if you're using npm, you can + install using npm install smoothscroll-anchor-polyfill + and then use the polyfill by requiring/importing it in your JS.

+ +
// Import any polyfill to enable smoothscroll for JS APIs
 import smoothscrollPolyfill from 'smoothscroll-polyfill';
+
 // Import this package to apply the smoothscroll to anchor links
-import 'smoothscroll-anchor-polyfill';
+import smoothscrollAnchorPolyfill from 'smoothscroll-anchor-polyfill';
 
-// Enable the main smoothscroll polyfill (might not be neccessary if you use an alternative one)
+// (Unlike this package, smoothscroll-polyfill needs to be actively invoked: )
 smoothscrollPolyfill.polyfill();
 
-

Advanced (with Code Splitting)

-

If you're using a build system with support for code splitting like - Parcel or Webpack, - you can use dynamic imports to load the polyfills – this way, - browsers won't even download the polyfill code if they already have - support for the Scroll Behavior spec natively:

- -
// Only continue if polyfills are actually needed
+          

Advanced installation (with Code + Splitting)

+

If you're using a build system with support for code splitting + like + Parcel or Webpack, + you can use dynamic imports to load the polyfills – this way, + browsers won't even download the polyfill code if they already have + support for the Scroll Behavior spec natively:

+ +
// Only continue if polyfills are actually needed
 if (!('scrollBehavior') in document.documentElement.style) {
 
   // Wait until the Polyfills are loaded
@@ -147,25 +193,41 @@ 

Advanced (with Code Splitting)

]) // then use the modules however you want .then(([smoothscrollPolyfill, smoothscrollAnchorPolyfill]) => { - // e.g. enable the main smoothscroll polyfill (might not be neccessary if you use an alternative one) + // (Unlike this package, smoothscroll-polyfill needs to be actively invoked: ) smoothscroll.polyfill(); }); }
-
-

Docs

-

There's not much more to it than loading this polyfill – it will +

+

Docs

+

For 90% of use cases, there should not be much more to it than + loading this polyfill – it will execute immediately no matter if loaded through a script tag or in a CommonJS environment. If the Scroll Behavior spec is supported natively, the code won't do anything.

-

⚠ Remember to also set the scroll-behavior property - globally (on html) - in your CSS, otherwise your site will behave differently in browsers - with and without support for the Scroll Behavior spec! ⚠

-

Use the Polyfill even if there is native - support

+

Changing the scroll behavior

+

The prefered way to dynamically adjust the scroll behavior is the font-family workaround. This way you can + simply toggle a CSS class on <html> depending on the + behavior you want. Valid property values are smooth for + enabling smooth scroll and auto, initial, + inherit or unset for enabling instant, + jumping scroll.

+
+

You can also assign these values directly to document.documentElement.style.scrollBehavior, + it will have precedence over both the inline style attribute and + the + property set using the font-family workaround.

+
+

+ ⚠ Assigning to .scrollBehavior is not recommened + however as this property is used for feature detection. Assigning to + it before a polyfill was loaded will break this one and most other + polyfills related to smooth scrolling. ⚠

+

Using the polyfill even if there is native + support

window.__forceSmoothscrollAnchorPolyfill__: @@ -176,29 +238,112 @@

Use the Polyfill even if there is native native smooth scroll. Not recommended.

-

Polyfill anchors dynamically inserted later

+

Methods: destroy and polyfill

+
+

This package exports two methods, destroy and polyfill. + If loaded through a script tag, these methods are exposed on + window.smoothscrollAnchorPolyfill.

+
+
+
+ destroy(): +
+
+

The polyfill runs automatically when it's loaded, setting up + the EventListeners it needs. This method disables the + polyfill and removes all EventListeners.

+
+
+
+
+ polyfill({ force: boolean }): +
+
+

If you used destroy() to disable the polyfill, + you can re-enable it with this method. It takes an (optional) + Object as argument, the property force behaves + the same way as the global force flag + on window.

+
+
+

⚠ Note that both the global force flag + and the + check for native + support ('scrollBehavior' in document.documentElement.style) + will be re-evaluated when polyfill() runs. If you + assigned to .scrollBehavior in the + meantime, this check will evaluate to true and the + polyfill won't enable itself. + Use the force flag or run delete document.documentElement.style.scrollBehavior; + if you encounter this problem.

+

Limitations

+

scroll-behavior is + not + detected in regular + stylesheets

+

As already explained in the Usage section, + scroll-behavior + can not be set in regular CSS, as accessing the property there + from JavaScript is not possible without a performance hit. This + is caused by browsers not parsing a CSS property if it isn't + recognized as valid. If you need the flexiblity of CSS, consider + the font-family + workaround.

+

scroll-behavior is only + supported + as global setting

+

In browsers with native support, you can define scroll-behavior + at multiple points in your document, e.g. auto on + the document itself, but smooth on a slideshow + container that has separate scrolling. This polyfill does not + allow for that, either all anchors on the page scroll smoothly by + setting scroll-behavior + at document level, or none.

+ +

This actually doesn't have anything to do with this polyfill – + it's a limitation of Blink's native implementation (so it affects + other Blink-based browsers like Opera, too). While 'normal' + scrolling is smooth, if you click a couple of links and then + navigate back and forth using the browser's forwards/backwards + buttons (which triggers a hashchange + everytime), it jumps from anchor to anchor instead of scrolling + smoothly. If this is important to you, you can fix it by + detecting the Blink engine and force-enabling this polyfill. Load + browsengine.js, + then do (before the polyfill runs):

+
if (window.webpage.engine.blink) {
+  window.__forceSmoothscrollAnchorPolyfill__ = true;
+}
+

FAQ

+

Will this break Server Side Rendering?

+

No.

+

Polyfill anchors dynamically inserted + later

The polyfill uses Event Delegation to detect clicks, so even if an anchor is added to the page after the polyfill was loaded, everything should work.

-

Disable the polyfill

-

There currently is no way to disable the polyfill once it was - loaded. I considered adding this functionality but couldn't think of - a good use case – if you have one, let me know!

-

💡 Note that even if global scroll-behavior is set and - this polyfill is loaded, you can still perform instant, jumping - navigation by using one of the JavaScript scroll APIs and specifying - { behavior: 'instant' } in the options object.

-

Will this break Server Side Rendering?

-

No.

+

Does this support prefers-reduced-motion?

+

prefers-reduced-motion is a relatively new CSS media + query that hints at whether a client prefers less motion, which can + be important for people with certain illnesses. But Safari is the + only browser that has implemented it yet, and it doesn't support the + Scroll Behavior spec, so there is no reference for the interplay of + prefers-reduced-motion and Scroll Behavior yet. For this + reason, it is not implemented (yet) in this polyfill.
+ However, it is relatively safe to assume that prefers-reduced-motion + will disable scroll-behavior: smooth so this can + absolutely be discussed – please file an issue on GitHub if it + affects your project.

-