gatsbyjs / gatsby

The best React-based framework with performance, scalability and security built in.
https://www.gatsbyjs.com
MIT License
55.28k stars 10.31k forks source link

Anchor Links / Hash in URL is ignored on initial page load #21120

Closed sidyes closed 4 years ago

sidyes commented 4 years ago

Description

I am having a SPA built with gatsby. I am using <a href="/#sectionX">section x</a> links for navigation in the header. This is working just fine.
Unfortunately, reloading the page (having the anchor link in the URL) does not scroll to the expected section but stays unscrolled at the top of the page.

Steps to reproduce

Take any gatsby starter, add anchor link, reload page.

Expected result

Page should automatically scroll to desired section as provided in the URL on initial page load.

Actual result

Hash is ignored and page does not scroll

Environment

System: OS: Windows 10 10.0.17763 CPU: (8) x64 Intel(R) Core(TM) i7-4770 CPU @ 3.40GHz Binaries: Node: 12.13.0 - C:\Program Files\nodejs\node.EXE npm: 6.12.0 - C:\Program Files\nodejs\npm.CMD Languages: Python: 2.7.17 Browsers: Edge: 44.17763.831.0

danspratling commented 4 years ago

Looks like gatsby takes control of the scroll position but you can use the gatsby-browser.js file to add a function to re-enable anchor links.

exports.onRouteUpdate = ({ location }) => scrollToAnchor(location)

/**
 *
 * @desc - a function to jump to the correct scroll position
 * @param {Object} location -
 * @param {Number} [mainNavHeight] - the height of any persistent nav -> document.querySelector(`nav`)
 */
function scrollToAnchor(location, mainNavHeight = 0) {
  // Check for location so build does not fail
  if (location && location.hash) {
    const item = document.querySelector(`${location.hash}`).offsetTop

    window.scrollTo({
      top: item - mainNavHeight,
      behavior: "smooth",
    })
  }

  return true
}

I'm not sure if the default browser behaviour for anchor links being disabled is intentional or not though. Would be worth getting some feedback from someone on the internal team.

sidyes commented 4 years ago

@danspratling: Thank you! It is working now - but as you said it would be really interesting what the intention of this really is from someone official.

I let this thread open for now to get hopefully an anweser.

github-actions[bot] commented 4 years ago

Hiya!

This issue has gone quiet. Spooky quiet. πŸ‘»

We get a lot of issues, so we currently close issues after 30 days of inactivity. It’s been at least 20 days since the last update here. If we missed this issue or if you want to keep it open, please reply here. You can also add the label "not stale" to keep this issue open! As a friendly reminder: the best way to see this issue, or any other, fixed is to open a Pull Request. Check out gatsby.dev/contribute for more information about opening PRs, triaging issues, and contributing!

Thanks for being a part of the Gatsby community! πŸ’ͺπŸ’œ

admackin commented 4 years ago

Yep this has bitten me too!

karlhorky commented 4 years ago

@danspratling you'll want to also update the scrollToAnchor function with the following, to fix ids starting with numbers, which results in an error like SyntaxError: Failed to execute 'querySelector' on 'Document': '...' is not a valid selector.:

// Fix scrolling for ids starting with numbers
// https://stackoverflow.com/a/20306237/1268612
const hash = location.hash.replace(/^#(\d)/, '#\\3$1');
blainekasten commented 4 years ago

Fixed in latest!

dmaxchristiansen commented 1 year ago

It looks like this issue is presenting itself again in Gatsby v5

sykoivisto commented 1 year ago

Still showing this issue in 5.8.1

danspratling's fix is still working

Looks like gatsby takes control of the scroll position but you can use the gatsby-browser.js file to add a function to re-enable anchor links.

exports.onRouteUpdate = ({ location }) => scrollToAnchor(location)

/**
 *
 * @desc - a function to jump to the correct scroll position
 * @param {Object} location -
 * @param {Number} [mainNavHeight] - the height of any persistent nav -> document.querySelector(`nav`)
 */
function scrollToAnchor(location, mainNavHeight = 0) {
  // Check for location so build does not fail
  if (location && location.hash) {
    const item = document.querySelector(`${location.hash}`).offsetTop

    window.scrollTo({
      top: item - mainNavHeight,
      behavior: "smooth",
    })
  }

  return true
}

I'm not sure if the default browser behaviour for anchor links being disabled is intentional or not though. Would be worth getting some feedback from someone on the internal team.