Fragment-linked elements concealed by sticky headers


#1

Elements that have an id attribute can be linked to via an URL with a fragment, as you probably know. However, there is an issue if the web page has a position: fixed sticky header: The browser does not take the header into account when setting the scroll position, and as a result, the top portion of the linked element (usually the element’s heading) is concealed by the sticky header.

Demo: http://exploringjs.com/es6/ch_callables.html#_cheat-sheet-callable-entities

I’m sure you’ve all experienced this issue before; I think it’s relatively common. How should we approach fixing this issue? A browser intervention? Maybe browsers could make sure that position: sticky elements never conceal fragment-linked elements. (This could also be defined in the appropriate CSS spec.) Then websites could start using sticky for their sticky headers as a best practice.


#2

Specs don’t define the precise scroll position for anchor scrolling. It should be fine for browsers to intelligently adjust the scroll value to avoid things like sticky headers.


#3
:target {margin-top: 5em;}

#4

Not a great solution because:

  1. Element may already have a margin-top, so you’d need to know the original value and add the offset length you want.
  2. It creates a strange blank in the layout. I’ve tried this solution on a project and had a project manager and client both tell me that it was not satisfying (and I tend to agree).

Definitely a problem we have on most projects.


#5

I didn’t claim it was “a great solution”, but I also don’t quite get why an existing margin-top value would be a show stopper when you just want to avoid something being covered by a sticky element – at least unless you scroll up which would make the altered top margin become visible. Something similar to :target:focus would be needed, or animate the 5em (or whatever) margin back to its original value over 2s or so, producing some auto-scrolling.

The real declarative solution would of course be something like

.sticky {
  visibility: occupy; /* or */
  visibility: static; /* or */
  z-index: all;
}

On the other hand, it should be a non-issue (safe browser bugs) with grid layouts.


#6

It won’t work for everyone, but I’ve been using a modified version of the solution at the link below.

Basically I use: <a name="mytarget"></a> Then: a[name] {position: relative; top: -100px;}

You can apply it however you want (whatever element + CSS), but I’ve found that using an anchor seems to work better for keyboard navigation anyway.


#7

I was about to propose an addition to that effect as well. :slight_smile: My suggestion is to add an attribute that controls this. Something like - <tagname id="anchorname" name="anchorname" anchorvisibility="auto"> (The accepted values would be “auto” or “manual”, I guess and the default is unfortunately “manual”) In addition, there could be a document level toggle - <meta http-equiv="Anchor-Visibility" content="auto"> And maybe also a manifest level toggle - "anchor-visibility": "auto"


#8

For the record, I would like this to be solved by browsers automatically. Chrome has recently shipped scroll anchoring (available in Canary), and it seems to work great. I don’t see why browsers couldn’t similarly solve this problem as well. Linking to page fragments should Just Work™.

@phistuck I’m curious what types of web compat issues would prevent this from defaulting to auto.


#9

Parallax scrolling comes to mind. People do weird things.


#10

Also, this API should generally make sure an anchor is visible to the user, whether it is position: sticky, fixed, absolute or anything else that obscures it (as long as scrolling makes it visible, obviously. It does not explicitly change the layout to make an element visible).


#11

We can go further - anchorvisibility="scroll" can scroll to make it visible, anchorvisibility="always" can make layout changes (z-index, hide other elements, whatever) and anchorvisibility="manual" can behave as it currently behaves. But that is probably an overkill. :slight_smile:


#12

This doesn’t belong at the HTML level; it’s a styling issue. The Scroll Snap spec defines the ‘scroll-padding’ property which should be used in this case - if you put in some scroll padding for the area under the fixed/sticky header, following an anchor should automatically scroll it so that the anchor is in the visible region, PgUp/PgDn scrolls by a visible screenful, etc.