© 2020 Pyotek
This site has amplified superpowers.

AMP: How to handle fixed header bars

The Problem

Using fixed-positioned header bars (or top navigation bars) is way more complicated when using AMP than it should be. To grant an optimal user experience, you have to consider three possible contexts:

  1. AMP page
  2. AMP page with blocked JavaScript (no AMP runtime execution)
  3. AMP page in AMP Viewer (such as Google’s)

Usually, the first two contexts are not a big problem. The last one is.

Here’s why: When using Google’s AMP viewer, Google uses its own header bar when rendering the page:

The Google bar is interferring with our own bar. That doesn’t look pretty, does it? So let’s fix it!

Note that the header bar will automatically disappear while scrolling though, as the following GIF shows:

Still – this overlay does not look professional.

First attempt

One way to handle this would be to change your bar to a “sticky” one, as shown in the following CSS:

.bar {
    height: 50px;
    position: sticky; /* was 'fixed before' */
    z-index: 999;
    width: 100%;
    top: 0;

Does it help with the overlaying Google bar? Yes, strangely – it does.

But it has one major disadvantage: The bar will just disappear. When the user scrolls, the bar will also be “scrolled away”! Sacrificing good user experience just for a better display inside a highly specialized viewer? Nah, that is not really worth it.

Final solution

So, what we need is to detect if the user uses an AMP viewer to read our content. Then our strategy would be: Use the fixed bar outside of an AMP viewer and use the sticky bar positioning only when inside an AMP viewer. This way, user expierence would only be sacrificed in AMP viewers.

Luckily, AMP has something to offer to accomplish this task: amp-dynamic-css-classes!

The amp-viewer class will be set if the current document is being displayed inside a Viewer.

For utility, we add the following CSS:

body:not(.amp-viewer) .if-viewer,
body.amp-viewer .if-not-viewer {
    display: none;

This is essentially a “double negation” that enables you to use the if-viewer and if-not-viewer classes in your HTML to show (or hide) elements only if in an AMP viewer (or not).

For our initial problem, we still need to adapt the bar’s CSS to the following:

.bar {
    height: 50px;
    position: fixed;
    z-index: 999;
    width: 100%;
    top: 0;
.bar body.amp-viewer {
    position: sticky

See the new .bar body.ampviewer rule? This does the magic. It overrides the bar positioning (which is now fixed again per default) to a sticky one if, and only if an AMP viewer is used.

That’s it. This is how we currently handle fixed header bars as you can also compare when visiting this site via AMP and directly.