[jquery] How to disable anchor "jump" when loading a page?

I think this may not be possible, will try and explain as best as I can. I have a page containing tabs (jquery powered), controlled by the following:

I'm using this code, as provided by another user from a previous question.

<script type="text/javascript">
    $(function() {

     $('html, body').animate({scrollTop:0}); // this is my "fix"

        var tabContent = $(".tab_content");
        var tabs = $("#menu li");
        var hash = window.location.hash;
     tabContent.not(hash).hide();
        if(hash=="") {
      $('#tab1').fadeIn();
     }
        tabs.find('[href=' + hash + ']').parent().addClass('active');

        tabs.click(function() {
            $(this).addClass('active').siblings().removeClass('active');
            tabContent.hide();
            var activeTab = $(this).find("a").attr("href");

            $(activeTab).fadeIn();
           return false;
        });

    });
</script>

this code works great when I visit the "tabs" page directly.

however, I need to link to invidual tabs from other pages - so to do this, the code gets the window.location.hash then shows the appropiate tab.

the page doesn't "jump" to the anchor because of "return false".

this event is only triggered on a click event however. hence, if i visit my "tabs" from any other page, the "jump" effect is triggered. To combat this I automatically scroll to teh top of the page, but I would rather this didn't happen.

is there any way to simulate "return false" when the page loads, preventing the anchor "jump" from occuring.

hope this is clear enough.

thanks

This question is related to jquery tabs href

The answer is


I think I've found a way for UI Tabs without redoing the functionality. So far I haven't found any problems.

    $( ".tabs" ).tabs();
    $( ".tabs" ).not(".noHash").bind("tabsshow", function(event, ui) { 
        window.location.hash = "tab_"+ui.tab.hash.replace(/#/,"");
        return false;
    });

    var selectedTabHash = window.location.hash.replace(/tab_/,"");
    var index = $( ".tabs li a" ).index($(".tabs li a[href='"+selectedTabHash+"']"));
    $( ".tabs" ).not(".noHash").tabs('select', index);

All within a ready event. It prepends "tab_" for the hash but work both when clicked and page loaded with hash.


This will work with bootstrap v3

_x000D_
_x000D_
$(document).ready(function() {_x000D_
  if ($('.nav-tabs').length) {_x000D_
    var hash = window.location.hash;_x000D_
    var hashEl = $('ul.nav a[href="' + hash + '"]');_x000D_
    hash && hashEl.tab('show');_x000D_
_x000D_
    $('.nav-tabs a').click(function(e) {_x000D_
      e.preventDefault();_x000D_
      $(this).tab('show');_x000D_
      window.location.hash = this.hash;_x000D_
    });_x000D_
_x000D_
    // Change tab on hashchange_x000D_
    window.addEventListener('hashchange', function() {_x000D_
      var changedHash = window.location.hash;_x000D_
      changedHash && $('ul.nav a[href="' + changedHash + '"]').tab('show');_x000D_
    }, false);_x000D_
  }_x000D_
});
_x000D_
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.0/css/bootstrap.min.css">_x000D_
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>_x000D_
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.0/js/bootstrap.min.js"></script>_x000D_
<div class="container">_x000D_
<ul class="nav nav-tabs">_x000D_
  <li class="active"><a data-toggle="tab" href="#home">Home</a></li>_x000D_
  <li><a data-toggle="tab" href="#menu1">Menu 1</a></li>_x000D_
</ul>_x000D_
_x000D_
<div class="tab-content">_x000D_
  <div id="home" class="tab-pane fade in active">_x000D_
    <h3>HOME</h3>_x000D_
    <p>Some content.</p>_x000D_
  </div>_x000D_
  <div id="menu1" class="tab-pane fade">_x000D_
    <h3>Menu 1</h3>_x000D_
    <p>Some content in menu 1.</p>_x000D_
  </div>_x000D_
</div>_x000D_
</div>
_x000D_
_x000D_
_x000D_


dirty CSS only fix to stay scrolled up every time the anchor is used (not useful if you still want to use anchors for scroll-jumps, very useful for deeplinking):

.elementsWithAnchorIds::before {
   content: "";
   display: block;
   height: 9999px;
   margin-top: -9999px; //higher thin page height
}

I have not had any consistent success with these solutions.

Apparently due to the fact that the jump happens before Javascript => reference(http://forum.jquery.com/topic/preventing-anchor-jump)

My solution is to position all anchors at the top by default with CSS.

.scroll-target{position:fixed;top:0;left:0;}

Then use jquery to scroll to the parent of the target anchor, or a sibling(maybe an empty em tag)

<a class="scroll-target" name="section3"></a><em>&nbsp</em>

jquery example for scrolling for when URL is entered with hash
(page must not be already loaded in window/tab, this covers links from other/outside sources)

setTimeout(function() {
    if (window.location.hash) {               
        var hash = window.location.hash.substr(1);   
        var scrollPos = $('.scroll-target[name="'+hash+'"]').siblings('em').offset().top; 
        $("html, body").animate({ scrollTop: scrollPos }, 1000);    
    }
}, 1);

Also you'll want to prevent default for anchor clicks while on the page and then scroll to their targets

<a class="scroll-to" href="#section3">section three</a>

and jquery

$('a.scroll-to').click(function(){
    var target = $(this).attr('href').substr(1);
    var scrollPos = $('.scroll-target[name="'+target+'"]').siblings('em').offset().top; 
    $("html, body").animate({ scrollTop: scrollPos }, 1000);
    return false;
});

The good thing about this method is the anchor tag targets, remain structurally beside the relevant content, although their CSS position is at the top.

This should mean that search engine crawlers won't have a problem.

Cheers, I hope this helps
Gray


  1. Browser jumps to <element id="abc" /> if there are http://site.com/#abc hash in the address and the element with id="abc" is visible. So, you just should hide the element by default: <element id="anchor" style="display: none" />. If there is no visible element with id=hash at the page, the browser would not jump.

  2. Create a script that checks the hash in url, and then finds and shows the prrpopriate element (that is hidden by default).

  3. Disable default "hash-like link" behaviour by binding an onclick event to a link and specify return false; as a result of onclick event.

When I implemented tabs, I wrote something like that:

    <script>
    $(function () {         
        if (location.hash != "") {
            selectPersonalTab(location.hash);
        }
        else {
            selectPersonalTab("#cards");
        }
    });

    function selectPersonalTab(hash) {
        $("#personal li").removeClass("active");
        $("a[href$=" + hash + "]").closest("li").addClass("active");
        $("#personaldata > div").hide();
        location.hash = hash;
        $(hash).show();
    }

    $("#personal li a").click(function (e) {
        var t = e.target;
        if (t.href.indexOf("#") != -1) {
            var hash = t.href.substr(t.href.indexOf("#"));
            selectPersonalTab(hash);
            return false;
        }
    });
</script>

See my answer here: Stackoverflow Answer

The trick is to just remove the hashtag ASAP and store its value for your own use:

It is important that you do not put that part of the code in the $() or $(window).load() functions as it would be too late and the browser already has moved to the tag.

// store the hash (DON'T put this code inside the $() function, it has to be executed 
// right away before the browser can start scrolling!
var target = window.location.hash,
    target = target.replace('#', '');

// delete hash so the page won't scroll to it
window.location.hash = "";

// now whenever you are ready do whatever you want
// (in this case I use jQuery to scroll to the tag after the page has loaded)
$(window).on('load', function() {
    if (target) {
        $('html, body').animate({
            scrollTop: $("#" + target).offset().top
        }, 700, 'swing', function () {});
    }
});

Try this to prevent client from any kind of vertical scrolling on hashchanged (inside your event handler):

var sct = document.body.scrollTop;
document.location.hash = '#next'; // or other manipulation
document.body.scrollTop = sct;

(browser redraw)


While the accepted answer does work well, I did find that sometimes, especially on pages containing large images that the scroll bar will jump about wildly using

 window.scrollTo(0, 0);

Which can be quite distracting for the user.

The solution I settled on in the end is actually pretty simple, and that's to use a different ID on the target to the one used in location.hash

Eg:

Here is the link on some other page

<a href="/page/with/tabs#tab2">Some info found in tab2 on tabs page</a>

So of course if there is an element with an ID of tab2 on the tabs page the window will jump to it on load.

So you can append something to the ID to prevent it:

<div id="tab2-noScroll">tab2 content</div>

And then you can append "-noScroll" to location.hash in the javascript:

<script type="text/javascript">
    $(function() {

        var tabContent = $(".tab_content");
        var tabs = $("#menu li");
        var hash = window.location.hash;


     tabContent.not(hash + '-noScroll').hide();                           
        if(hash=="") {       //^ here
      $('#tab1-noScroll').fadeIn();
     }
        tabs.find('[href=' + hash + ']').parent().addClass('active');

        tabs.click(function() {
            $(this).addClass('active').siblings().removeClass('active');
            tabContent.hide();
            var activeTab = $(this).find("a").attr("href") + '-noScroll'; 
                                                               //^ and here

            $(activeTab).fadeIn();
           return false;
        });

    });
</script>

I did not have much success with the above setTimeout methods in Firefox.

Instead of a setTimeout, I've used an onload function:

window.onload = function () {
    if (location.hash) {
        window.scrollTo(0, 0);
    }
};

It's still very glitchy, unfortunately.


Solved my promlem by doing this:

// navbar height 
var navHeigth = $('nav.navbar').height();    

// Scroll to anchor function
var scrollToAnchor = function(hash) {
  // If got a hash
  if (hash) {
    // Scroll to the top (prevention for Chrome)
    window.scrollTo(0, 0);
    // Anchor element
    var term = $(hash);

    // If element with hash id is defined
    if (term) {

      // Get top offset, including header height
      var scrollto = term.offset().top - navHeigth;

      // Capture id value
      var id = term.attr('id');
      // Capture name value
      var name = term.attr('name');

      // Remove attributes for FF scroll prevention
      term.removeAttr('id').removeAttr('name');
      // Scroll to element
      $('html, body').animate({scrollTop:scrollto}, 0);

      // Returning id and name after .5sec for the next scroll
      setTimeout(function() {
        term.attr('id', id).attr('name', name);
      }, 500);
    }
  }
};

// if we are opening the page by url
if (location.hash) {
  scrollToAnchor(location.hash);
}

// preventing default click on links with an anchor
$('a[href*="#"]').click(function(e) {
  e.preventDefault();
  // hash value
  var hash = this.href.substr(this.href.indexOf("#"));
  scrollToAnchor(hash);
});`

None of answers do not work good enough for me, I see page jumping to anchor and then to top for some solutions, some answers do not work at all, may be things changed for years. Hope my function will help to someone.

/**
 * Prevent automatic scrolling of page to anchor by browser after loading of page.
 * Do not call this function in $(...) or $(window).on('load', ...),
 * it should be called earlier, as soon as possible.
 */
function preventAnchorScroll() {
    var scrollToTop = function () {
        $(window).scrollTop(0);
    };
    if (window.location.hash) {
        // handler is executed at most once
        $(window).one('scroll', scrollToTop);
    }

    // make sure to release scroll 1 second after document readiness
    // to avoid negative UX
    $(function () {
        setTimeout(
            function () {
                $(window).off('scroll', scrollToTop);
            },
            1000
        );
    });
}

There are other ways of tracking what tab you're on; perhaps setting a cookie, or a value in a hidden field, etc etc.

I would say that if you don't want the page jumping on load, you would be better off using one of these other options rather than the hash, because the main reason for using the hash in preference to them is to allow exactly what you're wanting to block.

Another point - the page won't jump if your hash links don't match the names of the tags in the document, so perhaps if you want to keep using the hash you could manipulate the content so that the tags are named differently. If you use a consistent prefix, you will still be able to use Javascript to jump between then.

Hope that helps.


In my case because of using anchor link for CSS popup I've used this way:

Just save the pageYOffset first thing on click and then set the ScrollTop to that:

$(document).on('click','yourtarget',function(){
        var st=window.pageYOffset;
        $('html, body').animate({
                'scrollTop' : st
            });
});

I used dave1010's solution, but it was a bit jumpy when I put it inside the $().ready function. So I did this: (not inside the $().ready)

    if (location.hash) {               // do the test straight away
        window.scrollTo(0, 0);         // execute it straight away
        setTimeout(function() {
            window.scrollTo(0, 0);     // run it a bit later also for browser compatibility
        }, 1);
    }

Another approach

Try checking if the page has been scrolled and only then reset position:

var scrolled = false;

$(window).scroll(function(){
  scrolled = true;
});

if ( window.location.hash && scrolled ) {
  $(window).scrollTop( 0 );
}

Heres a demo


Examples related to jquery

How to make a variable accessible outside a function? Jquery assiging class to th in a table Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Getting all files in directory with ajax Bootstrap 4 multiselect dropdown Cross-Origin Read Blocking (CORB) bootstrap 4 file input doesn't show the file name Jquery AJAX: No 'Access-Control-Allow-Origin' header is present on the requested resource how to remove json object key and value.?

Examples related to tabs

Visual Studio Code - Convert spaces to tabs Sublime Text 3, convert spaces to tabs Bootstrap 3: Keep selected tab on page refresh Change tab bar tint color on iOS 7 Stacked Tabs in Bootstrap 3 C++ printing spaces or tabs given a user input integer Open link in new tab or window How to make a new line or tab in <string> XML (eclipse/android)? Find Active Tab using jQuery and Twitter Bootstrap How to make the tab character 4 spaces instead of 8 spaces in nano?

Examples related to href

File URL "Not allowed to load local resource" in the Internet Browser Angular 2 router no base href set How to redirect to a route in laravel 5 by using href tag if I'm not using blade or any template? Html- how to disable <a href>? Add php variable inside echo statement as href link address? ASP MVC href to a controller/view href="tel:" and mobile numbers How can I disable the bootstrap hover color for links? How can I disable HREF if onclick is executed? Open link in new tab or window