Coder Social home page Coder Social logo

scroll-behavior-polyfill's Introduction

Logo

A polyfill for the 'scroll-behavior' CSS-property

Downloads per month NPM version Dependencies Contributors code style: prettier License: MIT Support on Patreon

Description

The scroll-behavior CSS-property as well as the extensions to the Element interface in the CSSOM View Module CSS property sets the behavior for a scrolling box when scrolling is triggered by the navigation or CSSOM scrolling APIs. This polyfill brings this new feature to all browsers.

It is very efficient, tiny, and works with the latest browser technologies such as Shadow DOM.

This polyfill also implements the extensions to the Element interface in the CSSOM View Module such as Element.prototype.scroll, Element.prototype.scrollTo, Element.protype.scrollBy, and Element.prototype.scrollIntoView.

Features

  • Spec-compliant
  • Tiny
  • Efficient
  • Works with the latest browser technologies, including Shadow DOM
  • Seamless

Table of Contents

Install

NPM

$ npm install scroll-behavior-polyfill

Yarn

$ yarn add scroll-behavior-polyfill

Applying the polyfill

The polyfill will be feature detected and applied if and only if the browser doesn't support the property already. To include it, add this somewhere:

import "scroll-behavior-polyfill";

However, it is strongly suggested that you only include the polyfill for browsers that doesn't already support scroll-behavior. One way to do so is with an async import:

if (!("scrollBehavior" in document.documentElement.style)) {
	await import("scroll-behavior-polyfill");
}

Alternatively, you can use Polyfill.app which uses this polyfill and takes care of only loading the polyfill if needed as well as adding the language features that the polyfill depends on (See dependencies).

Usage

Declarative API

You can define the scroll-behavior of Elements via one of the following approaches:

  • A style attribute including a scroll-behavior property.
  • An element with a scroll-behavior attribute.
  • Or, an element with a CSSStyleDeclaration with a scrollBehavior property.

This means that either of the following approaches will work:

<!-- Works just fine when given in the 'style' attribute -->
<div style="scroll-behavior: smooth"></div>
<!-- Works just fine when given as an attribute of the name 'scroll-behavior' -->
<div scroll-behavior="smooth"></div>

<script>
	// Works jut fine when given as a style property
	element.style.scrollBehavior = "smooth";
</script>

See this section for information about why scroll-behavior values provided in stylesheets won't be discovered by the polyfill.

Imperative API

You can of course also use the imperative scroll(), scrollTo, scrollBy, and scrollIntoView APIs and provide scroll-behavior options.

For example:

// Works for the window object
window.scroll({
	behavior: "smooth",
	top: 100,
	left: 0
});

// Works for any element (and supports all options)
myElement.scrollIntoView();

myElement.scrollBy({
	behavior: "smooth",
	top: 50,
	left: 0
});

You can also use the scrollTop and scrollLeft setters, both of which works with the polyfill too:

element.scrollTop += 100;
element.scrollLeft += 50;

Dependencies & Browser support

This polyfill is distributed in ES3-compatible syntax, but is using some modern APIs and language features which must be available:

  • requestAnimationFrame
  • Object.getOwnPropertyDescriptor
  • Object.defineProperty

For by far the most browsers, these features will already be natively available. Generally, I would highly recommend using something like Polyfill.app which takes care of this stuff automatically.

Contributing

Do you want to contribute? Awesome! Please follow these recommendations.

Maintainers

Frederik Wessberg
Frederik Wessberg
Twitter: @FredWessberg
Lead Developer

Backers

Patreon

Become a backer and get your name, avatar, and Twitter handle listed here.

Backers on Patreon

FAQ

Are there any known quirks?

License

MIT © Frederik Wessberg (@FredWessberg) (Website)

scroll-behavior-polyfill's People

Contributors

wessberg avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

scroll-behavior-polyfill's Issues

Issue with dynamic import: "'index.d.ts' is not a module"

Hello. I have installed the library and dynamically import it when required. However, I receive the following error:

File '/path/to/project/node_modules/scroll-behavior-polyfill/dist/index.d.ts' is not a module.

Since index.d.ts clearly exists at that location, I assume there is something wrong with my TypeScript configuration. I cannot seem to find an option which fixes the issue. Any ideas?

My current tsconfig.json file:

{
    "compilerOptions": {
        "allowSyntheticDefaultImports": true,
        "allowUnreachableCode": false,
        "declaration": false,
        "experimentalDecorators": true,
        "lib": [
            "dom",
            "es2015"
        ],
        "moduleResolution": "node",
        "module": "esnext",
        "target": "es2017",
        "noUnusedLocals": true,
        "noUnusedParameters": true,
        "jsx": "react",
        "jsxFactory": "h"
    },
    "include": [
        "src"
    ],
    "exclude": [
        "node_modules"
    ]
}

Thank you for you assistance.

Comparison to iamdustan/smoothscroll

Hi, thanks for creating this library. I'm evaluating this pollyfill vs iamdustan/smoothscroll. Dustin's library is older has much more usage. What inspired you to write scroll-behavior-polyfill? How does it compare to dustin's library?

FWIW I appreciate that scroll-behavior-polyfill is written in typescript. A comparison vs alternatives would be a useful addition to the README.

Thanks!

anchor detection if the link also contains a path fails

https://github.com/wessberg/scroll-behavior-polyfill/blob/45593dcfc35f98b64230579eb01ac821c5d9f67d/src/patch/anchor/catch-navigation.ts

The catch-navigation currently looks if a link is clicked with href="#anchor" but it will never catch a link to the current page using href="/url/to/current/page#anchor" because only the attribute value is considered and only if it contains nothing else.

The detection for a link pointing to the current page is actually fairly simple:

const link = e.target;
const pointsToCurrentPage =
       link.origin === location.origin
    && link.pathname === location.pathname
    && link.search === location.search;

const hash = link.hash

Here is a reproduction: https://jsfiddle.net/ey087v3o/ (tested in safari and chrome)

not compatible with SSR

doesnt work when you import into a SSR app.

you should add

if(typeof window !== 'undefined')

before kicking off the polyfill

node >= 9.0.0

Hey Frederik!
I have question about this node version requirement:
https://github.com/wessberg/scroll-behavior-polyfill/blob/master/package.json#L66

Is it really required? I'm curious if transpiled/compiled package can be used with other node versions.
I have tried it and it works well with 8.12.0 version. We have 8.12.0 node version in our package.json

I had to install package with --ignore-engines yarn flag on my dev env
yarn add scroll-behavior-polyfill --dev --ignore-engines

But this blocks me from using your package on prod build. Can you reduce node version?

TypeError: e is not an Object. (evaluating '"style"in e')

Hi,

Our app is seeing errors logged from this package. Occurrences mostly look to be on iOS. Hopefully this would be an easy fix to the package.

TypeError: e is not an Object. (evaluating '"style"in e')
  File "webpack:///./node_modules/scroll-behavior-polyfill/dist/index.js", line 125, in s
            var target = "style" in inputTarget ? inputTarget : getScrollingElement();
  File "webpack:///./node_modules/scroll-behavior-polyfill/dist/index.js", line 484, in [anonymous]
            var behavior = getScrollBehavior(element, options);
  File "webpack:///./node_modules/scroll-behavior-polyfill/dist/index.js", line 475, in x
            onScrollWithOptions(getScrollToOptionsWithValidation(optionsOrX, y), element, kind);
  File "webpack:///./node_modules/scroll-behavior-polyfill/dist/index.js", line 576, in [anonymous]
                handleScrollMethod(this, "scrollTo", optionsOrX, y);
  File "https://app.joinswoop.com/auth/password_requests/dcfe98a0-b707-4cb4-855b-cbe172b856f7", line 1, in global code

catchNavigation click causes error when using hash for routing

// Attempt to match the selector from that root. querySelector' doesn't support IDs that start with a digit, so work around that limitation
const elementMatch = hash.match(ID_WITH_LEADING_DIGIT_REGEXP) != null ? root.getElementById(hash.slice(1)) : root.querySelector(hash);

hash from an anchor is passed directly to root.querySelector with our regard for what might be contained in the hash.

Hash-routing libraries store the route in the hash. For example an anchor tag may have #!/foo/bar as the value for the href.

Passing this value to root.querySelector causes an error, for example SyntaxError: The string did not match the expected pattern. in safari or Uncaught DOMException: Document.querySelector: '#!/foo' is not a valid selector in FIrefox.

This could be solved in two ways:

  1. a simple try/catch
  2. further expand the regex to allow for detecting a valid query selector string before passing it to querySelector

@wessberg if you have a preference between the two approaches (or have an alternative suggestion) I am happy to open a PR that fixes the bad assumption around what can live in a hash.

Support for non-object syntax.

MDN shows the scroll syntax as following:

window.scroll(x-coord, y-coord)
window.scroll(options)

This polyfill only seems to work using the options syntax.

Polyfilled smooth scroll slower than native implementations with long distances

I found that current computations for the polyfilled smooth scroll behavior make scrolling take a long time to 'ramp up' when scrolling over longer distances, like 'back to top' from a long list (several screen lengths) of search results, which makes such an action seem unresponsive. This is different from implementations in Chrome and Firefox, which appear 'snappier' in these cases.

Would it be possible to take another look at the code for animated scrolling, or make this configurable?

`scroll-padding` is ignored

When scrolling into view with block: 'start', it seems scroll-padding is ignored. It should offset the final scroll position.

scrollIntoView should default to block: "start"

I believe scrollIntoView should default to block: "start", but appears to be defaulting to block: "center". This causes behavior differences from browsers with the built-in helpers; and also means smooth scrolled anchor links are not scrolling to the same position as non-smooth scrolled anchor links.

TypeScript 3.5 compatibility issue

Repro:

https://github.com/laat/scroll-behavior-polyfill-ts3.5

tsc output:

node_modules/scroll-behavior-polyfill/dist/index.d.ts:5:9 - error TS2669: Augmentations for the global scope can only be directly nested in external modules or ambient module declarations.

5 declare global {
          ~~~~~~


Found 1 error.

local patch I currently use to fix the issue

diff --git a/node_modules/scroll-behavior-polyfill/dist/index.d.ts b/node_modules/scroll-behavior-polyfill/dist/index.d.ts
index 0ef8139..5ef52be 100644
--- a/node_modules/scroll-behavior-polyfill/dist/index.d.ts
+++ b/node_modules/scroll-behavior-polyfill/dist/index.d.ts
@@ -10,4 +10,5 @@ declare global {
         };
     }
 }
+export {};

Uncaught SyntaxError: Failed to execute 'querySelector' on 'Document': 'xxx' is not a valid selector.

'xxx' is a router path.

Look at this:

please <router-link :to="{ path: 'value' }">click here</router-link> to do something.

when click event fired, an error appeared in develop tools, xxx is a route path ('#/my/path') in my vue file, not an element id.

index.js error at line 715:

var elementMatch = hash.match(ID_WITH_LEADING_DIGIT_REGEXP) != null ? root.getElementById(hash.slice(1)) : root.querySelector(hash);

Cannot read property 'set' of undefined

For old Android Chrome users (version < 80), the polyfill can throw an error - Cannot read property 'set' of undefined.
The following changes:

var ELEMENT_ORIGINAL_SCROLL_TOP_SET_DESCRIPTOR = UNSUPPORTED_ENVIRONMENT
        ? undefined
        : (Object.getOwnPropertyDescriptor(Element.prototype, "scrollTop")||{}).set;

and

    var ELEMENT_ORIGINAL_SCROLL_LEFT_SET_DESCRIPTOR = UNSUPPORTED_ENVIRONMENT
        ? undefined
        : (Object.getOwnPropertyDescriptor(Element.prototype, "scrollLeft")||{}).set;

will let it fail silently.

Polyfill is not applied in Edge 87 & Chrome 87 (Windows 10)

Thanks for this awesome polyfill! Great job!

I've encountered a problem. Sometimes polyfill is not applied because these two checks return true...

image

...while the smooth scrolling doesn't work.

What do you think about providing a way to force apply the polyfill? For example, by prepending the polyfill import with window.forcePolyfillScrollBehavior = true;.

css scroll-snap fights scroll animation

There is now pretty good support for css scroll snap. But when used with this polyfill (in safari) the scroll snap points and this polyfill kind of fight for control.

There are no callbacks or anything to try it but i'd like to set scroll-snap-type to none during the animation.

So I either need callbacks or maybe even an implementation of what i'm trying... or both.

IE 11 HTMLElement.scrollIntoView() doesn't execute

Firstly, great polyfill – it works perfectly for scrollTo, however I'm unable to get scrollIntoView working.

Environment

IE 11 on Windows 10

Expected behaviour

When I call HTMLElement.scrollIntoView, I expect the page to scroll to the element.

Current Behaviour

When I call HTMLElement.scrollIntoView nothing happens; no console errors, no scroll, nothing.

Implementation

I have a function which I call, that looks like this:

async function scrollToSection(section) {
    if (!('scrollBehavior' in document.documentElement.style)) {
        console.log('Loading scroll behaviour polyfill...');
        await import('scroll-behavior-polyfill');
    }
    const container = document.querySelector(`.Section--${section}`);
    container && container.scrollIntoView();
}

My scrolling element is a custom element (so not the html or body elements). Do you think this is what could be causing the issue?

As a work-around, I've done this:

async function scrollTo(scrollContainer, {x, y, behavior = 'smooth'}) {
    if (!('scrollBehavior' in document.documentElement.style)) {
        console.log('Loading scroll behaviour polyfill...');
        await import('scroll-behavior-polyfill');
    }
    scrollContainer.scrollTo({left: x, top: y, behavior});
}

function scrollToSection(section) {
    const scrollContainer = document.querySelector('#root-app');
    const container = document.querySelector(`.Section--${section}`);
    if (container) {
        const {top} = container.getBoundingClientRect();
        scrollTo(scrollContainer, {y: top});
    }
}

Doesn't work in Safari

This doesn't seem to provide a polyfill for Safari when using:
scroll-behavior: smooth
on a non-root element.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.