48

I'm using the latest version of the jQuery UI tabs. I have tabs positioned toward the bottom of the page.

Every time I click a tab, the screen jumps toward the top.

How can I prevent this from happening?

Please see this example:

http://5bosses.com/examples/tabs/sample_tabs.html

Rahul Gupta
  • 9,775
  • 7
  • 56
  • 69
Edward
  • 4,331
  • 4
  • 20
  • 6
  • 10
    Seriously mark the dude's answer correct. – Steph Rose Jun 15 '11 at 20:46
  • Seems that [Edward](http://stackoverflow.com/users/31869/edward) and [Edt](http://stackoverflow.com/users/32242/edt) are the same users :), considering they both post the same links and looking at this: http://forum.jquery.com/topic/jquery-jquery-ui-tabs-screen-jumps-to-top-when-clicked – Tomas Mar 24 '12 at 19:00
  • @JasonZ - yes there is. Tabs are not always used as navigation (but maybe you are just referring to the sample link, its broken so i am not sure) – schmoopy May 21 '13 at 17:29
  • Mike's answer doesn't work if the page is short. [I tried to provide a **complete solution**](http://stackoverflow.com/a/9856531/684229) which works in all situations (and ported to new jQueryUI). – Tomas Feb 14 '14 at 08:42

17 Answers17

75

If you're animating your tab transitions (ie. .tabs({ fx: { opacity: 'toggle' } });), then here's what's happening:

In most cases, the jumping isn't caused by the browser following the '#' link. The page jumps because at the midpoint of the animation between the two tab panes, both tab panes are fully transparent and hidden (as in display: none), so the effective height of the whole tabbed section becomes momentarily zero.

And if a zero-height tabbed section causes the page to be shorter, then the page will appear to jump up to compensate, when in reality it's simply resizing to fit the (momentarily) shorter content. Makes sense?

The best way to fix this is to set a fixed height for the tabbed section. If this is undesirable (because your tab content varies in height), then use this instead:

jQuery('#tabs').tabs({
    fx: { opacity: 'toggle' },
    select: function(event, ui) {
        jQuery(this).css('height', jQuery(this).height());
        jQuery(this).css('overflow', 'hidden');
    },
    show: function(event, ui) {
        jQuery(this).css('height', 'auto');
        jQuery(this).css('overflow', 'visible');
    }
});

It will set the computed height of the pane before the tab transition. Once the new tab has appeared, the height is set back to 'auto'. Overflow is set to 'hidden' to prevent content from breaking out of the pane when going from a short tab to a taller one.

This is what worked for me. Hope this helps.

Mike Petrovich
  • 751
  • 5
  • 3
  • 1
    This didn't work for me when the contents of each tab are pulled via ajax. Only after the initial load of a tab does that tab stop jumping to the top. – keithjgrant Aug 12 '11 at 19:06
  • 1
    This solution doesn't work if the **target** page is short - then the screen will jump to the top anyway. See solution in [my answer](http://stackoverflow.com/questions/243794/jquery-ui-tabs-causing-screen-to-jump#9856531) - seems to work in all situations. Nevertheless big thanks Mike for revealing the principle of the problem! Without being inspired by you, I wouldn't be able to do it! – Tomas Mar 24 '12 at 23:19
  • Very very nice solution; smooth tab transitions that totally solve the ops question. Award this man the answer! – Shawn J. Molloy Jun 11 '12 at 17:03
15

If you have something along these lines:

<a href="#" onclick="activateTab('tab1');">Tab 1</a>

Try adding return false; after the tab activation command:

<a href="#" onclick="activateTab('tab1'); return false;">Tab 1</a>
changelog
  • 4,646
  • 4
  • 35
  • 62
5

My guess is that you are animating your tab transitions? I am having the same problem, where the page scroll jumps back to the top with every click.

I found this in the jquery source:

 // Show a tab, animation prevents browser scrolling to fragment,

Sure enough, if I have this:

$('.tab_container > ul').tabs();    
$('.tab_container > ul').tabs({ fx: { height: 'toggle', opacity: 'toggle', duration: 'fast' } });

my code jumps to the top and is annoying (but there's animation). If I change that to this:

$('.tab_container > ul').tabs();    
//$('.tab_container > ul').tabs({ fx: { height: 'toggle', opacity: 'toggle', duration: 'fast' } });

there is no tab animation, but switching between tabs is smooth.

I found a way to make it scroll back, but it's not a proper fix, as the browser still jumps to the top after clicking a tab. The scroll happens between the events tabsselect and tabsshow, so the following code jumps back to your tab:

var scroll_to_x = 0;
var scroll_to_y = 0;
$('.ui-tabs-nav').bind('tabsselect', function(event, ui) {
    scroll_to_x = window.pageXOffset;
    scroll_to_y = window.pageYOffset;
});
$('.ui-tabs-nav').bind('tabsshow', function(event, ui) {
    window.scroll(scroll_to_x, scroll_to_y);
});

I'll post any more progress I make.

Brian Ramsay
  • 7,536
  • 8
  • 41
  • 52
5

I was given a solution for this...

How to stop screen from jumping up when tab is clicked:

Wrap the div that contains the tabs in a div with a fixed height.

See example here: http://5bosses.com/examples/tabs/sample_tabs.html

edt
  • 22,010
  • 30
  • 83
  • 118
4

I had the same problem with jquery ui's menu - a preventDefault() on the anchor's click event stops the page from scrolling back to the top:

 $("ul.ui-menu li a").click(function(e) {
      e.preventDefault();
 });
Zach Johnson
  • 123
  • 5
4

Mike's solution demonstrated the principle greatly but it has a big drawback - if the resultant page is short, the screen will jump to the top anyway! The only solution is to remember the scrollTop, and restore it after the tabs are switched. But before the restoration, enlarge the page (html tag) appropriatelly:

(edit - modified for new Jquery UI API + small improvement for large pages)

$(...).tabs({
    beforeActivate: function(event, ui) {
        $(this).data('scrollTop', $(window).scrollTop()); // save scrolltop
    },
    activate: function(event, ui) {
        if (!$(this).data('scrollTop')) { // there was no scrolltop before
            jQuery('html').css('height', 'auto'); // reset back to auto...
                    // this may not work on page where originally
                    // the html tag was of a fixed height...
            return;
        }
        //console.log('activate: scrolltop pred = ' + $(this).data('scrollTop') + ', nyni = ' + $(window).scrollTop());
        if ($(window).scrollTop() == $(this).data('scrollTop')) // the scrolltop was not moved
            return;                // nothing to be done
        // scrolltop moved - we need to fix it
        var min_height = $(this).data('scrollTop') + $(window).height();
            // minimum height the document must have to have that scrollTop
        if ($('html').outerHeight() < min_height) { // just a test to be sure
                            // but this test should be always true
            /* be sure to use $('html').height() instead of $(document).height()
               because the document height is always >= window height!
               Not what you want. And to handle potential html padding, be sure
               to use outerHeight instead!
                   Now enlarge the html tag (unfortunatelly cannot set
               $(document).height()) - we want to set min_height
               as html's outerHeight:
             */
            $('html').height(min_height -
                 ($('html').outerHeight() - $('html').height()));
        }
        $(window).scrollTop($(this).data('scrollTop')); // finally, set it back
    }
});

Works with the fx effect too.

Tomas
  • 57,621
  • 49
  • 238
  • 373
3

Try using event.preventDefault();. On the click event which is switching the tabs. My function looks like this:

    $(function() {
        var $tabs = $('#measureTabs').tabs();
        $(".btn-contiue").click(function (event) {
            event.preventDefault();
            $( "#measureTabs" ).tabs( "option", "active", $("#measureTabs").tabs   ('option', 'active')+1  );
        });
    });
2

Try just adding a min-height using css to each of the tab content areas ( not the tabs themselves ). That fixed it for me. :)

2

Thanks for your help. Good suggestion, but I tried before with no luck. I think JQuery UI may be overriding my efforts.

Here is the code per tab:

<li class=""><a href="#fragment-2"><span>Two</span></a></li>

I already tried this with no success:

<li class=""><a href="#fragment-2" onclick="return false;"><span>Two</span></a></li>

Here is a simple example (without return false): http://5bosses.com/examples/tabs/sample_tabs.html

Any other suggestions?

Edward
  • 4,331
  • 4
  • 20
  • 6
1
> var scroll_to_x = 0; var scroll_to_y =
> 0;
> $('.ui-tabs-nav').bind('tabsselect',
> function(event, ui) {
>     scroll_to_x = window.pageXOffset;
>     scroll_to_y = window.pageYOffset; }); $('.ui-tabs-nav').bind('tabsshow',
> function(event, ui) {
>     window.scroll(scroll_to_x, scroll_to_y); });

Thanks for your help! Please let me know what else you find.

The above function works (screen doesn't move permanently)... but, the screen is very wobbly on click.

Here is a simple example showing how clicking a tabs causes the screen to jump toward the top (without the above code): http://5bosses.com/examples/tabs/sample_tabs.html

Note that there's no animation being used.

edt
  • 22,010
  • 30
  • 83
  • 118
1

I had such a problem. My code was:

$("#tabs").tabs({
  hide: {
    effect: "fade",
    duration: "500"
  },
  show: {
    effect: "fade",
    duration: "500"
  }
});

I have simply removed show and it worked like a charm!

 $("#tabs").tabs({
      hide: {
        effect: "fade",
        duration: "500"
      }
 });
Zeihlis
  • 53
  • 1
  • 2
  • 7
1

There is a much more simple way which I discovered from the comments on this page that is to simply remove the href="#" and it will not jump to the top any more! I verified and it works for me. Cheers

Sameer Alibhai
  • 3,092
  • 4
  • 36
  • 36
1

I prefer to have an href="#" in my links that do not take the user anywhere, but you can do this as long as you add an onclick="return false;". The key, I guess, is not sending the user to "#", which depending on the browser seems to default as the top of the current page.

0

I had the same problem, plus mine were rotating on their own so if you were at the bottom of the page, the browser window would be scrolled up tot he top. Having a fixed height for the tab container worked for me. Kind of a weird thing still is that if you leave the window or tab and go back, it will still scroll. Not the end of the world, though.

0

replace the href="#" with href="javascript:void(0);" in 'a' element

works 100%

mike
  • 9
  • 1
0

I found in my case the tab href=#example1 was causing the page to jump to the position of the id. Adding a fixed height to the tabs made no difference so I just added:

$('.nav-tabs li a').click( function(e) { e.preventDefault(); });

-2

Did you tryed:

fx: {opacity:'toggle', duration:100}
FDisk
  • 8,493
  • 2
  • 47
  • 52