scroll-into-view / scroll-into-view-if-needed

Element.scrollIntoView ponyfills for things like "if-needed" and "smooth"

Home Page:https://scroll-into-view.dev

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Set block: nearest with offset?

bluecaret opened this issue · comments

I need to be able to scroll into view with block: 'nearest' but with an offset. So this means I can have it scroll to the bottom of a div, but provide some buffer space below so the div isn't on the exact bottom of the screen. The center option is too drastic for my use, I just need a buffer of 30 pixels or so but still want it at the bottom of the screen.

I'm hoping there is a way to do this, but if not then this would be a feature request :)

Hey!

Have you tried adding some CSS padding to your div?

If you look at the Custom Transition example on the demo and inline: "nearest" you can see how it's using a fixed width to apply an offset, it could just as well used padding to apply the offset:
image

If Element.scrollIntoView never scrolled more than one element (like document.body) an offset option would be reasonable to have.
It can be any number of elements though and I'm not sure how that would work. Should the offset apply to all of the scrolling boxes, or just window or document.body, or just the first one?

It's also possible for you to apply the offset yourself if you override the scrolling logic:

import scrollIntoView from "scroll-into-view-if-needed";

scrollIntoView(node, {
  behavior: actions =>
    actions.forEach(({ el, top, left }, i) => {
      // apply the 30px on the first scrolling box only
      el.scrollTop = i === 0 ? top - 30 : top;
      el.scrollLeft = left;
    })
});

Margins are excluded though. If your current CSS and HTML structure prevents you from being able to use padding on your div for this then I hope the custom behavior snippet above can help you 😄

Yes, I can't use padding, have to use margin, that's precisely my issue 😄

I tried the override and it works, but doesn't smooth scroll, just jumps to the position, I still need it to smoothly scroll to it. Any hope for that?

Thanks!

The best way to do that is by using CSS, add this next to where you are using overflow: scroll or overflow: auto:

scroll-behavior: smooth;

If that is not an option you can copy the logic the library is using internally to make smooth scrolling work without adding that CSS.

import scrollIntoView from "scroll-into-view-if-needed";

const supportsScrollBehavior =
  "scrollBehavior" in document.documentElement.style;

scrollIntoView(node, {
  behavior: actions =>
    actions.forEach(({ el, top: origTop, left }, i) => {
      // apply the 30px on the first scrolling box only
      const top = i === 0 ? origTop - 30 : origTop;

      // `Element.scroll` have historically worked the same way as `window.scrollTo`
      // Browsers like Safari does not support passing the new object variant
      // and that's why the extra `supportsScrollBehavior` check is necessary
      if (el.scroll && supportsScrollBehavior) {
        el.scroll({ top, left, behavior: "smooth" });
      } else {
        if (el === document.documentElement) {
          window.scrollTo(left, top);
        } else {
          el.scrollTop = top;
          el.scrollLeft = left;
        }
      }
    })
});

Interesting, did not know that was a CSS option! Learn something new 👍
Thanks!