Skip to content

Fix zoomed-in mobile swipes panning the page instead of the timeline - #906

Merged
JoeGermuska merged 1 commit into
masterfrom
fix/touch-action-swipe
Sep 22, 2026
Merged

JoeGermuska merged 1 commit into
masterfrom
fix/touch-action-swipe

Conversation

@JoeGermuska

Copy link
Copy Markdown
Member

Problem

On a phone, with the page zoomed in, some swipes on the timeline pan the whole page instead of moving to the next slide or scrolling the timenav.

Swipable._onDragMove only calls preventDefault() when a touchmove is more horizontal than vertical. The browser decides whether a gesture is a native pan on the first touchmove. So a swipe that starts slightly diagonal, or with a pixel of jitter, gets claimed by the browser, and the page pans instead.

Fix

Add touch-action: pan-y pinch-zoom to the two elements Swipable listens on:

  • .tl-slider-container-mask (story slider)
  • .tl-timenav-slider-background (timenav)

The browser now knows up front that horizontal drags on these elements belong to the page's JavaScript, while vertical scrolling and pinch-zoom stay native. This is CSS only; no JS changes.

Trade-off: while zoomed in, a horizontal drag that starts on the timeline no longer pans the page. You pan by dragging outside the timeline or by pinching. That's normal for a carousel-style widget.

Testing

  • npm test passes (123 tests), and npm run build compiles the rule into timeline.css and the theme CSS files.
  • In a 375px mobile-emulated browser, the computed touch-action is correct on both elements, and a synthetic touch swipe still advances slides.
  • Still needed: a check on a real phone. Desktop emulation doesn't reproduce how a real phone decides between panning and swiping. With the page zoomed in, swipe the story slider and the timenav several times, including slightly diagonal swipes.

Independent of #901 (JS modernization); either can merge first.

🤖 Generated with Claude Code

Swipable only calls preventDefault on a touchmove when that move is more
horizontal than vertical. Browsers decide whether a gesture is a native
pan on the first touchmove, so a swipe that starts slightly diagonal (or
with a pixel of jitter) gets claimed by the browser. When the page is
zoomed in, that pans the whole page instead of advancing the timeline.

Declare touch-action: pan-y pinch-zoom on the two Swipable drag targets
(the story slider mask and the timenav background) so horizontal drags
always go to Swipable, while vertical scrolling and pinch-zoom stay
native.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@JoeGermuska
JoeGermuska merged commit 7492344 into master Sep 22, 2026
@JoeGermuska
JoeGermuska deleted the fix/touch-action-swipe branch September 22, 2026 17:29
TheCause added a commit to TheCause/TimelineJS3 that referenced this pull request Sep 25, 2026
- Bump dompurify to ^3.4.16 resolving all production npm audit advisories
- Bump adm-zip to ^0.6.1
- Harden media types against XSS by removing direct innerHTML injections (Bluesky, DailyMotion, GoogleDoc, Vine)
- Remove obsolete IE/Edge browser check in PDF.js
- Add touch-action: pan-y pinch-zoom in StorySlider and TimeNav for mobile swipe gestures (PR NUKnightLab#906)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant