35

How can I focus to a HTML element (ex. "a") and do not change the current scroll settings.

For ex. if I use:

$('#link').focus();

and this link is not visible in the screen (ex. is bellow the visible area) the browser scrolls down to show the element. How can I set the focus without scrollbar movement? I need to stay the scrollbar in the original place.

I have tried this, but it produces some screen flickering, and it is a hack, not an elegant solution:

var st=$(document).scrollTop();
$('#link').focus();
$(document).scrollTop(st);

Can somebody help me, please?

buzoganylaszlo
  • 492
  • 1
  • 4
  • 8
  • Why would you want the focused control to not be visible? Perhaps there is another way to achieve the functionality you are looking for. – JoeyRobichaud Feb 04 '11 at 13:03
  • I am trying to make an image gallery. There are mini thumbnail images (which are the #link-s). I want bind a next and prev key event handler on that mini images which automaticaly shows the big image in an other part of the screen. And I don't want the browser go to the mini image, just to stay in the place that the big image shoul be visible. If I not change the focus I cannot bind the key events from the mini images... So it's complicated... – buzoganylaszlo Feb 04 '11 at 13:23
  • you may want to use setActive function for ie – llgcode Nov 05 '15 at 10:22

7 Answers7

46

Try this:

$.fn.focusWithoutScrolling = function(){
  var x = window.scrollX, y = window.scrollY;
  this.focus();
  window.scrollTo(x, y);
  return this; //chainability

};

and then

$('#link').focusWithoutScrolling();

Edit:

It's been reported that this doesn't work in IE10. The probable solution would be to use:

var x = $(document).scrollLeft(), y = $(document).scrollTop();

but I haven't tested it.

Felipe Martim
  • 1,151
  • 10
  • 11
8

Use {preventScroll: true} option on the focus method. https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus

If using jQuery try $('#el')[0].focus({preventScroll: true}) or iterate over each in your collection

marcusds
  • 784
  • 1
  • 7
  • 26
Dan Eastwell
  • 5,146
  • 4
  • 22
  • 34
  • 1
    Focus options are only supported in Chrome, if you check the link in the answer above you'll see that. But it is a good solution otherwise. You'll need to also put an preventDefault on the event in some cases too. – marcusds May 10 '18 at 16:54
  • No longer just Chrome, but most browsers except IE (Edge is fine though) and Safari. – curiousdannii Jan 14 '22 at 09:34
3

$('#link').css('position', 'fixed').focus().css('position', 'static') works in Firefox.

(Edit: You should not use this hack)

Dorian
  • 22,759
  • 8
  • 120
  • 116
jd.
  • 10,678
  • 3
  • 46
  • 55
  • 1
    Chrome seems to insist on scrolling to the focused element's position as soon as its CSS position property is set back to static or relative. I got a test that works if you wrap your target in a relatively positionned
    , the target getting an absolute position. I don't know how that would work in your particular case.
    – jd. Feb 04 '11 at 13:43
  • And also works in Chromium at least in 2023. – ZzZombo May 01 '23 at 12:50
2

The reason why this is so hard for you is because you aren't supposed to do it. The browsers are designed to help the user avoid websites that do stuff like this, because a link the has focus will activate by hitting return or space on the keyboard, and users rarely wish to follow a link they are not aware is there.

Try to work with the browser instead of against it, and you will usually end up with happier users.

Martin Jespersen
  • 25,743
  • 8
  • 56
  • 68
  • 1
    You could get around that by .focus on the element and immediately .blur() it – PHearst Apr 25 '13 at 07:53
  • 3
    I can see legitimate uses for wanting to have keyboard focus on an element that isn't on screen. I don't think jumping users around to the button they activated with a key press would make them happier. – Craig Brett Mar 25 '15 at 12:50
  • Hey PHearst... I tried ur logic but its working with first partial page control not for other partial pages control :( – user3217843 Sep 28 '16 at 09:50
  • 1
    I don't agree with this. This has nothing to do with security reasons. That doesn't make any sense. If someone wanted, they could just catch the enter key or spacebar and manually activate the link via JS. The only reason it scrolls is the browser expects this to be the desired behavior but there are legitimate times it wouldn't be. For example, I am loading a pop up window with a message and a reply box at the bottom. I want the reply box to be auto focused so someone can just start typing to compose a reply, but I want the window to always load at the top of the message. It's good UX design. – dallin Dec 18 '16 at 04:25
1

I have the same problem, but in words: I think a more elegant solution would be to give the focus once the element is in the viewport.

Here's what I copy/pasted (Kudos to ADB from this thread Jquery check if element is visible in viewport)

$.fn.inView = function(){
    if(!this.length) return false;
    var rect = this.get(0).getBoundingClientRect();

    return (
        rect.top >= 0 &&
        rect.left >= 0 &&
        rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
        rect.right <= (window.innerWidth || document.documentElement.clientWidth)
);

};



window.$(window).on('scroll',function(){ 

    if( $('#elementcontainingfocus').inView() ) {
       $(function() {
                $("#elementcontainingfocus input").focus();
                    $("input[type=text]:focus").css({  
                    "box-shadow": "0 0 5px rgba(81, 203, 238, 1)",
                    "border": "1px solid rgba(81, 203, 238, 1)"
                    });
                });
    }

});
Community
  • 1
  • 1
0

Try this jQuery solution:

$('#link').select();
josliber
  • 43,891
  • 12
  • 98
  • 133
Ripper
  • 1,132
  • 13
  • 26
  • 1
    That does accomplish nothing, it is related to text selection in input elements, it does not influence keyboard focus. – Martin Mar 09 '16 at 12:57
0

This worked for me

var focusWithoutScrolling = function(element) {
    var fixed = { "position": "fixed" };
    var posStatic = { "position": "static" };
    $(":root").css(fixed);
    $("body").css(fixed);
    $("html").css(fixed);
    $(element).focus();
    $(":root").css(posStatic);
    $("body").css(posStatic);
    $("html").css(posStatic);
}
Martin
  • 5,714
  • 2
  • 21
  • 41