Fixed header issue: prevent input fields from getting focus behind the header

I have a simple fixed header on a page and some form fields like this: https://codepen.io/anon/pen/xQYbPq

When I scroll down a little, focus on a text field and move back with focus to previous fields with Shift+Tab then I eventually reach a field that is behind the fixed header and the cursor is invisible and I can type into the field but will not see anything. I would expect the browser to scroll the page enough to make the focused field visible away from the fixed header. But browsers don’t seem to have any built-in mechanisms to work around the issue.

How can I solve this problem? Although a pure CSS solution would be the best I suspect there would need to be some js involved. I might code some js code for that but maybe there is a ready script already made by someone?

No there’s no automatic way to do this. A browser doesn’t care that you have placed content on top of something else. It can’t possibly know that something is accidentally covered by any absolutely (or fixed) positioned element.

I can’t think of an easy fix other than raising the z-index of the input so that it shows on top of the header when in focus but that would look very strange.

I think you will need to resort to JS to do this and test whether the element in focus is below the header or covered by it and then scroll appropriately. It could be a difficult task.

It might be easier to simply fade the header out altogether when one of the form elements has focus. Add a class to the header with js when the input is focussed and then remove it when complete.

These are the inherent problems of fixed headers and footers and they are not always easy to overcome and why I advocate using fixed elements with care. There are some fixed headers that only appear when you scroll back up the page and maybe something like that would lessen the chance of the inputs overlapping (although I guess the shift+tab would cause a scroll event and he header would appear over the input again).

Sorry I can’t think of anything useful :frowning:

That’s what I suspected but I was hoping that maybe someone thought about it in some modern CSS specification. Theoretically, browsers could support something like this:

header {
  position: fixed;
  reserve-as-header: top;
  ...
}

and this would instruct browsers that any space from the top of the page to the bottom of the header may cover other elements on the page and this could be used to fix focus issues like that and to account for scrolling to #hash URL’s. But for now this is in the realm of dreams…

This might be the way out and it doesn’t seem to be difficult - we would need to attach a focus event on all fields and then just get the vertical position of the focused field relative to viewport and if it is within the fixed header area scroll the page accordingly. The only problem left I can think of for the solution to be transparent is how to capture focus() function execution so that when I have a script that does this:

input.focus();

then my adjustment event also fires. Do you know a way around that? AFAIK, DOM events will not fire when the action is triggered by js like above.

I’ve just tested and it turns out that the input.focus() function fires the focus event so there should be no problem with it. I may write a script for that if I don’t find any better way soon.

1 Like

Here is my initial go at the script, seems to work fine in current desktop browsers:

var fixedfocus = {
	init: function(fixedElem) {
		fixedfocus.fixedElem = fixedElem;
		document.body.addEventListener('focusin', fixedfocus.adjust);
	},
	
	adjust: function(e) {
		var fixedBottomPos = fixedfocus.fixedElem.getBoundingClientRect().bottom;
		var rect = e.target.getBoundingClientRect();
		if (rect.top < fixedBottomPos) {
			window.scrollBy(0, rect.top - fixedBottomPos);
		}
	}
};

document.addEventListener('DOMContentLoaded', function() {
	fixedfocus.init(document.querySelector('header'));
});

2 Likes

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.