zudo-text

検索したい単語を入力

いつでも検索バーを開ける

Scroll sync

Scroll sync keeps two side-by-side panes scrolling together when they show the same note. Scroll one pane, the other follows; toggle it off, and each pane scrolls independently again. The most common use is keeping an editor + preview split aligned while you read your own writing back, but it works for any same-note pair where both panes are in a scrollable view mode.

Enabling scroll sync

The toggle lives on the divider between the two panes — the same divider you drag to resize the split. When the two panes form an eligible pair, a small link icon appears on the divider:

  • Inactive (link-off icon, dim) — scroll sync is available but currently off. Click the icon to turn it on.

  • Active (link icon, accented colour) — scroll sync is on. Click the icon again to turn it off.

The toggle is only rendered when the pair is eligible (see Eligibility rules below). When eligibility is lost — for example, you close the split, or one of the panes switches to a non-scrollable view mode — the toggle disappears and the engine detaches automatically. Re-creating the pair brings the toggle back, but the on/off state is not restored: each fresh pair starts in the off state.

The state is per-pair, not global. If you have several splits open in the future, each pair has its own independent toggle.

Eligibility rules

A pair of panes is eligible for scroll sync when all of the following are true:

  1. They are siblings in the split tree — i.e. the two panes that share a single divider. Scroll sync does not span across other splits.

  2. They show the same note. Looking at two different notes side by side is a separate workflow; sync only makes sense when the two scrolls are tracking the same content.

  3. Both panes are in a scrollable view mode. Today that means edit (the CodeMirror editor) and preview (the rendered Markdown). Non-scrollable surfaces such as kanban, todo, and mindmap are excluded — their layouts are not vertical streams, so a percentage-based scroll mapping has no meaningful target.

If you change the view mode of a pane while sync is on, the engine notices the change and re-anchors against the new scroll surface on the next render — there is no need to toggle the feature off and on again to keep things aligned after switching from preview back to edit, for example.

How it tracks scrolls

The MVP uses percentage mapping. When you scroll one pane to, say, 30% of its scrollable range, the engine writes the other pane to 30% of its scrollable range. The mapping is bidirectional: whichever pane you scroll becomes the source for that frame.

A few small pieces of machinery keep the experience smooth:

  • rAF batching — at most one synced write per animation frame, so a burst of native scroll events does not produce a burst of writes.

  • Loop suppression — programmatic scrolls are tagged so the resulting scroll event on the target pane does not echo back to the source.

  • Resize realignment — when the scroll height changes (an image loads in the preview, the editor wraps onto more lines), the engine re-aligns once from the most recently scrolled pane to the other.

Content-height normalization

The ratio is normalized against each pane's rendered content height, not the raw DOM scrollHeight. The editor's scrollPastEnd() virtual padding (which lets you scroll one viewport past the last source line for typing comfort) is excluded from the ratio basis, and the preview's content height is read directly. This way, scrolling to the last line on the editor side lands the preview at its last rendered line — even though the two scroll containers report different scrollHeight values.

Known limitation: percentage mapping is approximate

Because the MVP maps by percentage, vertical position in one pane is not always a perfect match for the same logical content in the other pane. In practice this is fine for normal prose, but you can see drift in two situations:

  • A note with very long fenced code blocks — the editor may show the full block on a few lines while the preview rendering uses far less or far more vertical space, depending on syntax highlighting and wrapping.

  • A note with many large images — image height in the preview depends on natural aspect ratio and is essentially unrelated to the source line count.

When this happens, the two panes will still track each other's scroll direction and roughly the same region of the document, but the exact line on top can differ. This residual mismatch — rendered-block-height ≠ source-line-height — is an inherent property of percentage-based sync and is what the planned data-line source-map mapper (Phase 2) will solve.

Coming later: line-precise mapping is on the roadmap. The plan is to drive sync from the source-line ↔ rendered-element correspondence the Markdown pipeline already knows about, instead of percentages. The engine has a ScrollMapper seam wired in for exactly this purpose, so the swap is intended to be additive — the public toggle and the eligibility rules above will not change.

Tips

  • Open a Preview Split View first. The "Preview Split View" command (Command Palette → "Preview Split View", or its keyboard shortcut) creates the canonical layout this feature was designed for: left pane in edit mode, right pane in preview mode, both showing the same note. The toggle appears immediately.

  • The toggle does not begin a divider drag. Clicks on the toggle stop propagation, so accidentally tapping it while reaching for the divider grip will not start a resize.

  • Use the Tab order normally. The toggle is a real <button> with aria-pressed reflecting state, so screen readers and keyboard navigation behave the way you would expect.

Reading side-by-side with sync OFF

Even when scroll sync is off, opening the same note in two panes is still useful for side-by-side reading. The preview pane will preserve its scroll position when the editor side is edited; the non-editing side will not jump to the bottom while you keep typing on the other side.