smooth-scroll-into-view-if-needed icon indicating copy to clipboard operation
smooth-scroll-into-view-if-needed copied to clipboard

Offset with smooth scroll

Open 0xsven opened this issue 5 years ago • 5 comments

I am trying to get a smooth scroll to an element with a sticky navigation bar.

Overriding behavior (to add an offset) also overrides the smooth scroll. Can someone give me some advice on how to make this work?

const scrollIntoViewSmoothly =
  'scrollBehavior' in document.documentElement.style
    ? scrollIntoView
    : smoothScrollIntoView

scrollIntoViewSmoothly(node, {
      block: 'start',
      behavior: (actions) =>
        actions.forEach(({ el, top, left }, i) => {
          el.scrollTop = i === 0 ? top - 90 : top
          el.scrollLeft = left
        }),
    })

0xsven avatar Sep 26 '18 15:09 0xsven

So I have worked around it by giving the element the style rule: padding-top: 90px and the element before the style rule: margin-bottom: -90px

0xsven avatar Sep 27 '18 08:09 0xsven

You can use custom transition with popmotion:

import { tween, styler, easing } from "popmotion";

scrollIntoView(node, {
  scrollMode: "if-needed",
  block: "nearest",
  inline: "nearest",
  behavior: instructions => {
    const [{ el, top }] = instructions;
    const elStyler = styler(el);
    tween({
      from: el.scrollTop,
      to: top - 90,
      ease: easing.easeLinear
    })
    .start(top => elStyler.set("scrollTop", top));
  }
});

vukadinFE avatar Feb 14 '19 11:02 vukadinFE

@stipsan This is a scenario I'm dealing with – I have a sticky navigation menu header. On click of any menu item, it scrolls to the required element. But because the header sticks, it hides the top of that element a little by virtue of Navigation Menu Header's height.

Does it make sense to allow an 'offset' value for top, so that the behaviour coded up smooth-scroll-into-view-if-needed can used directly through this module. Right now the only option I have is to copy paste smooth-scroll-into-view-if-needed's behaviour function and manually add my offset there and use it in my code.

arihantverma avatar Jan 22 '20 13:01 arihantverma

Alright I've had a rethink. Right now if you give behavior a callback this library will simply forward everything to scroll-into-view-if-needed and no animation happens unless the browser can do it natively, which is confusing and not very helpful since if that's what you need you should just use scroll-into-view-if-needed directly instead of this library.

I'll make a new major release that lets you map over the coordinates when you provide a custom behavior, applying offsets as needed:

// Given this markup:
// <div id="app" style="height: 100vh; overflow: auto;">
//   <header style="position: fixed; left: 0; top: 0; right: 0; height: 50px" />
//   <div id="hero" />
//   <footer id="contact-us" />
// </div>

import scrollIntoView from "smooth-scroll-into-view-if-needed";
const node = document.getElementById("contact-us");

scrollIntoView(node, {
  behavior: actions =>
    actions.map(action => {
      // Ensure the offset is only applied
      // to the element that needs it.
      if (action.el.matches("#app")) {
        // Apply the minimum needed scroll padding
        // to stay underneath the sticky header.
        action.top = Math.max(50, action.top);
      }

      return action;
    })
});

That'll solve these kind of challenges for now. In the long run I want to extend compute-scroll-into-view itself to support either https://css-tricks.com/almanac/properties/s/scroll-padding/ directly, or provide the API needed to build it in packages like scroll-into-view-if-needed. The scroll-margin|padding spec is only used in scroll snapping as far as I know, I'm not aware of any browsers supporting it for scrollIntoView and .focus APIs yet but I'm keeping an eye out for when that happens 😄

stipsan avatar Jan 22 '20 18:01 stipsan

Hello, I'm interested into that feature actually. Any news about its implementation? Thank you.

lbineau avatar Nov 17 '21 09:11 lbineau