Create a Seamless Scroll to Anchor Effect with JQuery and a Fixed Navigation Bar

I'm encountering an issue with smooth scrolling on a webpage that has a sticky header. When I click on a navigation link to scroll to a specific section using

scrollTop: href.offset().top - 100
, the page doesn't behave as expected. It seems to bounce back to the top after initially scrolling to the desired section. I am working in Microsoft Edge, and I suspect this may be contributing to the problem.

HTML

<!DOCTYPE HTML>
<html lang="en">
<head></head>
<body id="home">
    <nav><a href="#section1">Section #1</a></nav>
    <main>
        <!-- INSERT A BUNCH OF <BR> TAGS -->
        <h2 id="section1">section1</h2>
        <!-- INSERT A BUNCH OF <BR> TAGS -->
    </main>
</body>
</html>

CSS

nav {
    position:fixed;
    padding:4px;
border:2px solid #000;
width:100%;
    line-height:2.25em;
    background-color:yellow;
}

h2 {
    padding:4px;
    border:1px solid #000;
    width:100%;
    line-height:100px;
    background-color:red;
    }

jQuery

$(document).ready(function() {

    $('a[href*="#"]').click(function(event) {

        var href = $(this.hash);

        if (href.length) {
            event.preventDefault();
            $('html, body').animate({
                scrollTop: href.offset().top - 100
            }, 750, function() {
                location.hash = href.attr('id');
            });     
        }
    });
});

JSFiddle

EDIT:

I've learned that using display:fixed on a <div> element can cause it to be removed from the normal flow of the page, potentially causing issues like the one described above. I'm wondering if there's a workaround for this particular situation?

Answer №1

UPDATE:

Encountered difficulties with Edge and Firefox when attempting to adjust the behavior of hashchange. As a workaround, I have decided to omit the window.location.hash step to prevent sudden jumps post-animation. However, this is not an optimal solution as it interferes with the default hash location functionality.

$(document).ready(function() {
  $('a[href*="#"]').on('click', (event) => {
    const hash = event.currentTarget.hash;
    if (hash) {
      event.preventDefault();
      $('html, body').animate({scrollTop: $(hash).offset().top - 100}, 750);
    }
  });
});
nav {
  position: fixed;
  padding: 4px;
  border: 2px solid #000;
  width: 100%;
  line-height: 2.25em;
  background-color: yellow;
}

h2 {
  padding: 4px;
  border: 1px solid #000;
  width: 100%;
  line-height: 100px;
  background-color: red;
}
<!DOCTYPE HTML>
<html lang="en">
  <head>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
  </head>
  <body id="home">
    <!-- Navigation -->
    <nav><a href="#section1">Section #1</a></nav>
    <!-- Main Content -->
    <main>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <h2 id="section1">section1</h2>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
    </main>
  </body>
</html>

ORIGINAL METHOD:

The use of location.hash appears to trigger a scroll jump to the top following the completion of the scrollTop animation. To resolve this issue, modify the hashchange event to halt the scrolling at a set distance above your anchor elements in order to eliminate this unwanted jump.

$(document).ready(function() {
  $(window).on('hashchange', function() {
    window.scrollTo(window.scrollX, window.scrollY - 100);
  });

  $('a[href*="#"]').on('click', (event) => {
    const hash = event.currentTarget.hash;
    if (hash) {
      event.preventDefault();
      $('html, body').animate({
        scrollTop: $(hash).offset().top - 100
      }, 750, function() {
        window.location.hash = hash;
      });
    }
  });
});

Answer №2

Previous suggestions indicated that Microsoft Edge may have trouble properly supporting the .hash feature, leading to issues like the smooth scroll rebounding effect. To address this, I opted to utilize pushState for browsers that could support it, successfully achieving the desired functionality.

HTML

<!DOCTYPE HTML>
<html lang="en">
<head></head>
<body id="home">
    <nav><a href="#section1">Section #1</a></nav>
    <main>
        <!-- INSERT A BUNCH OF <BR> TAGS -->
        <h2 id="section1">section1</h2>
        <!-- INSERT A BUNCH OF <BR> TAGS -->
    </main>
</body>
</html>

CSS

nav {
    position: fixed;
    padding: 4px;
    border: 2px solid #000;
    width: 100%;
    line-height: 2.25em;
    background-color: yellow;
}

h2 {
    padding: 4px;
    border: 1px solid #000;
    width: 100%;
    line-height: 100px;
    background-color: red;
}

JAVASCRIPT

$('a[href*="#"]').click(function(event) {

    var href = $(this.hash);

    if (href.length) {
        event.preventDefault();
        $('html, body').animate({
            scrollTop: href.offset().top - 100
        }, 750, function() {
            if (history.pushState) {
                history.pushState(null, null, 'index.html#' + href.attr('id'));
            } else {
                location.hash = href.attr('id');
            }
        });     
    }
});

I encountered difficulty in dynamically retrieving the calling file name, such as index.html or main.html, to automatically generate the hashed URL. Thus, manual updates are needed per page. Despite this caveat, the implementation functions as intended. Refer to the JSFiddle example for a demonstration.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Update the FontSize in the HTML dropdown menu using JavaScript

I am having trouble filling my Selection using a script. For example, when I try to populate my FontSizeMenu, I use the following code snippet: function FillFontSizeMenu() { FillSelection(GetPossibleFontSizes(), "fontSizeMenu"); } function GetPossib ...

Updating React state via child components

Encountering a strange issue while working on a project, I managed to replicate it in this jsfiddle. The parent component's state seems to be affected when the child component updates its state. Any insights on what might be causing this? Here is the ...

Implementing a feature to automatically set the datepicker value to the selected date upon page initialization

I am working with a datepicker element, identified by id="from_dt", and a button with id="fromToDate". When a date is selected from the datepicker and the button is clicked, the page will load. At that point, I want to transfer the selected date to a textb ...

Unusual Occurrence: Unexpected Gap at the Beginning of HTML

There seems to be an issue with white space appearing unexpectedly at the top and right side of the file in a website I am working on. Despite adding margin: 0; padding: 0; to both <body> and <html>, the problem persists. After inspecting the ...

Exploring the Power of Laravel 5.5 and Vue.js 2.x for Efficient API Calls

Currently, I am working on a Laravel 5.5 project locally that incorporates Vue.js 2.5.9 with XAMP Server. One of the tasks I have is to load certain information onto the DOM and then refresh it upon clicking the "Refresh" button. However, there seems to ...

jquery filter not yielding the expected outcome

I am currently dealing with an empty sendStatus[]. Essentially, I need to check if a value exists in the array when a user clicks on a checkbox. If the value is not present, I want to add it as "add+this.value". If the user clicks on the checkbox again, I ...

Optimizing Shader Caching in WebGL: Best Practices

I am currently in the process of developing a WebGL application, and I have encountered some challenges with shader storage... In most examples, shaders are directly written in plaintext within the xHTML file itself. However, this approach can lead to clu ...

Why is this text appearing twice on my screen?

When I run the code in my React app and check the console in Chrome, I notice that the response.data[0] is being printed twice. What could be causing this duplication? const fetchData = async () => { return await axios.get(URL) .then((respon ...

Choose does not showcase the updated value

My form contains a form control for currency selection Each currency object has the properties {id: string; symbol: string}; Upon initialization, the currency select component loops through an array of currencies; After meeting a specific condition, I need ...

What is the best way to adjust the layout for smaller screens using material ui?

Just starting out with responsive material design. On smaller screens, the Sports Status needs to remain in the right corner. 4Standard, 5Standard, 6Standard, 7Standard, 8Standard, 9Standard should wrap to the next line. I came across this code snippet f ...

Struggling to make React respond to button clicks without resorting to using addEventListener

Can anyone help me figure out why I can't get the onclick handler to execute in reactjs when specifying it inline for a button? The only solution that worked for me was using addEventListener. From what I understand, this code should work: <button ...

Adjust the Pivot Point of a GLTF Model in ThreeJS Manually

Hey there, I have a GLTF model that I successfully loaded into my ThreeJS scene by using the code snippet below: gltfLoader.load('assets/models/coin/scene.gltf', (gltf) => { const root = gltf.scene; gltf.scene.traverse(functio ...

What could be causing my Vuex state to remain unchanged even after the nuxtServerInit commit?

Although I've been utilizing the nuxtServerInit method to retrieve data from my Contentful CMS and commit the mutation to update the categories state object, I keep encountering an issue where categories remain empty even after attempting to display t ...

Activating the Mobile Menu Function when the Window is Resized

I've developed a JavaScript function that triggers on window resize. When switching between landscape and portrait orientation on mobile devices or tablets, the window dimensions change. This functionality is also useful for browser testing on desktop ...

Transferring variables between vanilla JS and Angular 2: A guide

I am facing a challenge where I need to retrieve an object title from vanilla JavaScript and then access it in my Angular 2 component. Currently, I am storing the variable in localStorage, but I believe there must be a better approach. The issue arises wh ...

Cast your vote once for each post within the Angular application

Currently, users are only able to vote up or down once in general. I would like to allow users to vote up or down once per post. <div ng-repeat="post in posts | orderBy:'-upvotes'"> <span class="glyphicon glyphicon-thumbs-up" ...

Is it possible to customize the information displayed in a Mat-Dialog based on the object being

My current project involves the presentation of various boxes on a screen. Each box contains a button that, when clicked, redirects to another page. Here is the interface for the box object: export interface Allbox { image: string, link: string, ...

The clearInterval function in Javascript may not effectively halt an ongoing animation

Whenever I press a button, the element rotates using setInterval and clearInterval to stop rotation at a specific value by clearing the interval time t. Everything works perfectly except when I continually click the same button before the current animation ...

ng-repeat not functioning properly when using track by, filter, and orderBy

I have come across this code snippet. http://jsfiddle.net/0tgL7u6e/ Scripting in JavaScript var myApp = angular.module('myApp',[]); function MyCtrl($scope) { $scope.nameFilter = ''; $scope.contacts = [ {name: 'G ...

Scraping content using xpath in a complex html layout

I have a large amount of HTML code that I need to process using XPath. There are two different ways in which the text "The Text" can appear: <div> The Text </div> <!-- OR --> <div> <span>The Text</span> </div> ...