Skip to content

fix: keep anchor links aligned after layout changes#2731

Open
apples-kksk wants to merge 2 commits intodocsifyjs:developfrom
apples-kksk:fix-anchor-scroll-after-layout
Open

fix: keep anchor links aligned after layout changes#2731
apples-kksk wants to merge 2 commits intodocsifyjs:developfrom
apples-kksk:fix-anchor-scroll-after-layout

Conversation

@apples-kksk
Copy link
Copy Markdown

Summary

Direct links like #/?id=target can land too early when images or other content above the heading are still changing the page height. This keeps the requested heading aligned for a short settling window after the first scroll, and stops doing that as soon as the user starts interacting with the page.

I also added a Playwright regression that delays an image above the target heading and checks that the heading still ends up near the top of the viewport.

Related issue, if any:

Fixes #351

What kind of change does this PR introduce?

  • Bugfix
  • Feature
  • Code style update (formatting, renaming)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • Documentation content changes
  • Other (please describe):

For any code change,

  • Related documentation has been updated, if needed
  • Related tests have been added or updated, if needed

Does this PR introduce a breaking change?

  • Yes
  • No

Tested in the following browsers:

  • Chrome
  • Firefox
  • Safari
  • Edge

Checked locally with npm run lint, npm run build:js, npm run test:e2e:chromium -- anchor-scroll.test.js, and git diff --check.

@vercel
Copy link
Copy Markdown

vercel Bot commented May 9, 2026

@apples-kksk is attempting to deploy a commit to the Docsify Team on Vercel.

A member of the Team first needs to authorize it.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes anchor deep-link scrolling (#/?id=...) landing too early when late-loading content (e.g., images) above the target heading changes layout after the initial scroll, by re-aligning the target for a short settling window and stopping once the user interacts.

Changes:

  • Refactors anchor navigation scrolling into a dedicated #scrollToHeading() helper that re-syncs scroll position during a brief post-scroll window using ResizeObserver.
  • Adds a Playwright E2E regression test that simulates a delayed image above the anchor target.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
test/e2e/anchor-scroll.test.js Adds an E2E regression test for anchor alignment when an image above the target loads late.
src/core/event/index.js Implements post-scroll re-alignment logic for anchor targets during late layout changes and cancels on user interaction.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread test/e2e/anchor-scroll.test.js Outdated
Comment on lines +66 to +72
await expect
.poll(async () => {
return page.locator('#target-section').evaluate(el => {
return el.getBoundingClientRect().top;
});
})
.toBeLessThan(80);
Comment thread src/core/event/index.js
Comment on lines +673 to +676
window.addEventListener('load', resync, { once: true });
timers.max = setTimeout(cancel, 3000);
requestAnimationFrame(() => requestAnimationFrame(resync));

Comment thread src/core/event/index.js
Comment on lines +629 to +641
/** @param {ScrollBehavior} [behavior] */
const scrollToHeading = (behavior = 'smooth') => {
if (!document.contains(headingElm)) {
cancel();
return;
}

this.#watchNextScroll();
headingElm.scrollIntoView({
behavior,
block: 'start',
});
};
@apples-kksk
Copy link
Copy Markdown
Author

Addressed the review feedback in cf22daf: the regression test now waits for the delayed image to finish loading before checking the target, anchor resync stops after cancellation, and instant resyncs no longer register extra scroll watchers.\n\nVerified with:\n- npx prettier --check src/core/event/index.js test/e2e/anchor-scroll.test.js\n- npx eslint src/core/event/index.js test/e2e/anchor-scroll.test.js\n- npm run build:js\n- npm run test:e2e:chromium -- anchor-scroll.test.js

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.

Direct link to sub-item not scrolling to correct position

2 participants