Fragment-linked elements concealed by sticky headers

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.

3 Likes

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.

1 Like
:target {margin-top: 5em;}
1 Like

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.

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.

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.

2 Likes

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"

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.

Parallax scrolling comes to mind. People do weird things.

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).

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:

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.