WordPress Adminbar Sticky

WordPress Adminbar

In the attempt to remove as much of javascript as possible, certainly not relying on jquery and its ilk, we need a CSS-only sticky header and/or footer.

This is normally quite straightforward. However, the trick comes when logged into WordPress and the Adminbar is present.

If only the #mobile-header, .site-header, #site-navigation, or #masthead is needed for sticky, then voila:

/* sticky header */

#mobile-header, 
#masthead {
  position: -webkit-sticky;
  position: sticky; 
  top: 0px; 
}

Note that -webkit-sticky is needed to support Safari browsers before v.13 (Sep 2019).

Currently for the themes in GeneratePress that we are using, the #mobile-header and masthead are what works for us.

Adminbar Sticky

The Adminbar is either 32px or 64px in height depending on @media query. Therefore if the Adminbar is always present, simply add that many pixels to the top: directive.

/* sticky header */

#mobile-header, 
#masthead {
  position: -webkit-sticky; 
  position: sticky; 
  top: 32px; 
}

@media all and (max-width:782px) {
  #mobile-header, 
  #masthead {
    top: 46px; 
  }
}

The problem comes when there may be an admin bar, or may not be.

Sticky Adminbar Workarounds

There are several approaches to this, since CSS itself cannot detect the presence or absence of a class or id.

  1. Javascript (what we are trying to avoid)
  2. Hide the Adminbar altogether (cure is worse than the disease)
  3. Move Adminbar to the bottom (learning curve and all other sites have it at the top)
  4. Modify the header.php template to inject classes into the body based on logged-in status, then inject CSS via a function
  5. A cleaner approach to 4. which adds a spacer div into header.php and styles it.
  6. Add a header spacer div between the header and the content, and recalculate widths of that if Adminbar is present
  7. CSS Only

The first option of Javascript is what we are trying to avoid. The current GeneratePress theme loads jQuery when the sticky header is enabled (adding insult to injury).

The second two options are obvious work-arounds / hacks by either hiding or moving the Adminbar.

The fourth option requires editing a PHP template in the theme or a child theme. Not too difficult but if there is a non-PHP approach, that would be better. Note that the page linked above goes a bit nuts and adds the CSS via a function added to functions.php. This aims to be a PHP-only approach. Fair enough.

The fifth option adds a spacer div and immediately styles it, but that styling is limited to one size of the Adminbar, not both. In this case a @media query and css classes are needed.

The sixth option is the same as the fifth, except that the div is present whether logged-in or not and simply styled using blocks of css. This is the cleverer of the options above. It also means we can avoid editing the WordPress templates and/or PHP files directly, if we are using builder themes or theme frameworks that support hooks and allow us to inject divs where we wish (namely between the header and body).

The seventh option is of course the obvious choice. No PHP or additional <div>s needed.

CSS for Sticky Header with Adminbar

The key is that the class .admin-bar is added to the body when logged in. So if present, we add the

/* sticky header */

#mobile-header, 
#masthead {
  position: -webkit-sticky; 
  position: sticky; 
  top:0; 
}
.admin-bar #mobile-header, 
.admin-bar #masthead { 
  top: 32px; 
}
@media screen and (max-width: 782px) {
  .admin-bar #mobile-header, 
  .admin-bar #masthead { 
    top:46px; 
  }
}

There are a few tweaks we add for mobile.

  • For some sizes of the Adminbar, position:absolute; is added, but that breaks our sticky, so we have to add position:fixed;. We do this with the #wpadminbar id.
  • Also the .main-title (our text logo) and h1s are a bit big for this size, based on our standard desktop font sizes, so we change their sizes to 30px.
/* sticky header & wpadminbar support */

#mobile-header, 
#masthead {
  position: sticky; 
  position: -webkit-sticky;
  position: -top:0; 
}

.admin-bar #mobile-header, 
.admin-bar #masthead {
  top: 32px;
}

@media screen and (max-width: 782px) {
  .admin-bar #mobile-header, 
  .admin-bar #masthead {
    top: 46px;
  }
  #wpadminbar {
    position: fixed;
  }
  .main-title, h1 { 
    font-size:30px; 
  }
}

For mobile-first (if the adminbar is used more often when on mobile), reverse the order of the adminbar position sizes and use min-width:783px instead of max-width.