Conversation
Signed-off-by: Philipp Daun <post@philippdaun.net>
Signed-off-by: Philipp Daun <post@philippdaun.net>
There was a problem hiding this comment.
Pull Request Overview
Adds horizontal scrolling support and updates the scrollTo API to accept an object with both top and left offsets.
- Change
swup.scrollTosignature tonumber | { top, left } - Update internal calls and implementation to handle both axes
- Bind plugin’s
scrollTomethod directly to the Swup instance
Comments suppressed due to low confidence (3)
src/index.ts:405
- [nitpick] Update the doc comment to mention both horizontal and vertical offsets, for example: "Scroll to a specific top & left offset, with optional animation."
* Scroll to a specific offset, with optional animation.
src/index.ts:33
- New horizontal scrolling logic and API signature change should be covered by unit tests. Consider adding tests for
scrollTo({ top, left })and mixed number/object inputs.
scrollTo?: (
position: number | ScrollPosition,
src/index.ts:465
getOffsetlikely only returns a vertical offset. Subtracting it fromleftmay produce incorrect horizontal positioning. Consider calculating a separate horizontal offset or confirm thatgetOffsethandles both axes.
this.scrollTo({ top: top - offset, left: left - offset }, animate, scrollContainer);
|
Nice! Did you activate those Copilot reviews? I'm only on mobile right now, but the point about |
|
I asked him for fun :) Haven't looked at it, but makes sense to allow setting both top and left offsets if useful. |
|
For e2e tests - what do you think about using your playground for the fixtures? It's also astro, after all. |
Sure, we can copy them over. However the styling is a bit messy, so we might even be faster by just recreating the styles. |
|
Added support for vertical + horizontal offsets. |
src/index.ts
Outdated
| return offset; | ||
| } else { | ||
| const top = parseInt(String(offset ?? ''), 10) || 0; | ||
| return { top, left: top }; |
There was a problem hiding this comment.
If we treat a single number as top in scrollTo, I'd expect a single number for offset also to be treated as the top offset:
return { top, left: 0 };There was a problem hiding this comment.
Interesting. I'd expect it to have a uniform offset. Mentally, I see it a bit like the scroll-margin css property, which applies to all sides when set to a single value. Whereas scrolling always requires being explicit like in window.scrollTo(x, y)...
There was a problem hiding this comment.
Hmm. This would break expectations with how the offset used to work, at least for me.
But let's take a step back - would it make sense to start respecting the actual scroll-margin css value instead of the js version we provide right now? And only provide the offset callback? I don't know, happy to give this some more thought in a talk.
There was a problem hiding this comment.
From MDN:
The
scroll-margin-topproperty defines the top margin of the scroll snap area that is used for snapping this box to the snapport.
So Scratch that, it applies to anchor scrolling without any snapping as well – tested it myself just now.scroll-margin only seems to be related to scroll snapping, not to anchor scrolling, if I read this right? I have never used scroll-margin-* myself.
There was a problem hiding this comment.
I'd love to use scroll-margin exclusively, however it's not perfect. The package we're using to compute scroll movements does calculate it in, so it's good to go in that sense. The issue is with the actual spec/browser implementation. There's no way of defining cumulative offsets when nesting scroll containers. So I can't define an offset for scrolling the body (e.g. the header height) and a different offset for scrolling inside overflowing containers (e.g. 1em). Happy to show you in a call how it behaves in the playground.
There was a problem hiding this comment.
All that to say: it's a great idea to use scroll-margin for 90% of use cases. Just when targeting elements inside scroll containers, it gets tricky and requires some custom JS logic.
There was a problem hiding this comment.
Ah yes, scroll margin applies to all scrolling. Took me a while to figure that out myself :)
There was a problem hiding this comment.
I'd love to use
scroll-marginexclusively, however it's not perfect. The package we're using to compute scroll movements does calculate it in, so it's good to go in that sense. The issue is with the actual spec/browser implementation. There's no way of defining cumulative offsets when nesting scroll containers. So I can't define an offset for scrolling the body (e.g. the header height) and a different offset for scrolling inside overflowing containers (e.g. 1em). Happy to show you in a call how it behaves in the playground.
Yes please, I would love that!
Ok, maybe recreating the styles is the better idea. I used tailwind for the fixtures, which helps a lot with creating multiple independent pages / one-off styles. |
src/index.ts
Outdated
| offset: | ||
| | number | ||
| | ScrollPosition | ||
| | ((scrollTarget?: Element, scrollContainer?: Element) => number | ScrollPosition); |
There was a problem hiding this comment.
I just stumbled upon this: Are scrollTarget and scrollContainer not always defined? getOffset is only being called by scrollElementIntoView(), where both are always defined.
There was a problem hiding this comment.
I'm currently confused – is the offset to be applied when doing a normal scroll to top (without a scrollTarget)? If so, getOffset should be changed to this:
((scrollContainer: Element, scrollTarget?: Element) => number | ScrollPosition)There was a problem hiding this comment.
True, these should always be defined. We can probably safely change the signature.
There was a problem hiding this comment.
The offset is only applied when scrolling to an element. When scrolling to the top, it wouldn't have an effect. Subtracting the offset would end up with a scroll position below zero, so still technically the top.
There was a problem hiding this comment.
I have no idea why we made these arguments optional. Maybe I bungled it while adding the feature :)
There was a problem hiding this comment.
Thank you for clearing that up with the negative scroll offset 😅🫠
|
Note from recent call: make |
|
...and: clamp offsets so that the scroll target will be revealed completely, even if at the far edges of the scroll container. |
✅ Deploy Preview for swup-scroll-plugin ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
This makes it possible for consumers what to do when scrolling to the far edges of a container (should the an offset be substracted or not)
|
I've implemented the last missing pieces and added them to the top comment:
The third is the best I could come up with to enable users to clamp offsets so that the scroll target will be revealed completely, even if at the far edges of the scroll container. I think it's best to not make any assumptions about what everybody wants here. In the playground code, I could then return /**
* Do not offset the scroll if scrolling to the very end
*/
const maxTop = container.scrollHeight - container.clientHeight;
if (top === maxTop) return 0;What do you think? |
Description
scrollTofrom justnumbertonumber | { top: number, left: number }OffsetCallbackto{ top: number, left: 0}OffsetCallbackarguments are never undefinedOffsetCallbackto provide fine-grained controlExample from playground
Checks
nextbranchnpm run lint)All tests are passing (npm run test)New or updated tests are included