Skip to content

WordPress Header

Header setup

How to do a hero with full height less menu header height. This takes into account the WordPress admin bar when logged in.

There are three states of the admin bar:

  • (max-width: 600px) has a height of 46px, bar scrolls away
  • (max-width: 782px) has a height of 46px, bar is fixed at top of screen
  • (min-width: 783px) has a height of 32px, bar is fixed at top of screen

The header (which will typically contain the logo and menu) will have a fixed height which is set with the custom property --header-height. Breakpoints can also be added if the height changes, for example smaller screens will often have a smaller header.

The header uses .sticky now that IE is not supported. The advantage is that you don't need to worry about adding a top margin to the main element.

/*--------------------------------------------------------------
# Header 
--------------------------------------------------------------*/

:root {
  --header-height: 88px; /* Mobile height */
  
  @media screen(menu) {
    --header-height: 80px; /* Desktop height */
  }

  @media screen(3xl) {
    --header-height: 160px; /* Desktop height */
  }
}

.site-header {
  height: var(--header-height);

  .admin-bar & {
    top: 32px;

    @media screen and (max-width: 782px) {
      top: 46px;
    }
  }
}

/* Break point at which WP header scrolls away */
@media screen and (max-width: 600px) {
  .admin-bar {

    /* starts off static */
    .site-header {
      position: static; 
    }

    /* sticky-admin class is added with js */
    &.sticky-admin .site-header {
      top: 0;
      position: fixed;
    }

  }
}

Html in header.php.

<header class="sticky flex items-center justify-between bg-slate-500 px-7 xl:px-14 2xl:px-36 site-header">
		
  <div class="">

    <!-- Logo -->
    <a href="<?php echo esc_url( home_url( '/' ) ); ?>" rel="home">
      <?php
        $custom_logo_id = get_theme_mod( 'custom_logo' );
        $image_path = get_attached_file( $custom_logo_id );
        if ( $image_path ) {
          echo file_get_contents( $image_path );
        }
      ?>
    </a>

  </div>

  <nav class="main-navigation">
    
    <button class="menu-toggle" aria-controls="menu-modal" aria-expanded="false">

      <?php
        wp_nav_menu( 
          array(
            'theme_location'  => 'main_menu',
            'menu_class'      => 'main-menu',
            'container'       => false
          )
        ); 
      ?>

    </button>

  </nav>

</header>

Sticky admin bar

We need to handles the case where up to a max-width of 600px the admin bar scrolls away. To manage this, add a file /js/admin.js that will add the class sticky-admin to the body element when the page has scrolled 46px (the height of the admin bar).

function makeStickyOnScroll() {
  // set container to make sticky.
  var stickyContainerAdmin = document.querySelector("body");

  // set scroll distance, 46 is the height of the wordpress mobile navbar
  var scrollDistanceAdmin = 46;

  // Listen for scroll
  function handleScroll() {
    if (window.pageYOffset > scrollDistanceAdmin) {
      stickyContainerAdmin.classList.add("sticky-admin");
    } else {
      stickyContainerAdmin.classList.remove("sticky-admin");
    }
  });

  // Initial call on page load
  handleScroll();

  // Listen for scroll
  window.addEventListener("scroll", handleScroll);
}

document.addEventListener("DOMContentLoaded", makeStickyOnScroll);

Then add to functions.php with the rest of the wp_enqueue_scripts.

if( is_user_logged_in() ) {
  wp_enqueue_script( 'projectX-admin', get_template_directory_uri() . '/js/admin.js', array(), false, true );
}

Uses the built-in sr-only and not-sr-only from Tailwind CSS with some minor additional styling for the focused state. The z-[99999] ensures the link is shown above the WordPress admin bar.

<a class="sr-only focus:not-sr-only bg-white z-[99999] rounded outline-none  focus:px-4 focus:py-3 focus:absolute focus:ring-2 focus:ring-black focus:top-1 focus:left-1" href="#main">
  Skip to content
</a>

Alternate Colour Header

When some pages have a dark header while others have a light header.

Add to functions.php so all pages with a dark header will have a class of dark-header added to the body element.

/**
* Add body class for dark / light header
*/
add_filter('body_class', 'my_body_classes');
function my_body_classes($classes) {
 
  if ( 
    is_page_template('page-templates/home.php') or 
    is_page_template('page-templates/about.php') or 
    is_page_template('page-templates/contact.php')
  ) {
    $classes[] = 'dark-header';
  }
 
  return $classes;
}

Change :root to body so css custom properties can be overridden correctly.

Example css.

.site-header {
  @apply bg-white;
  
  .dark-header & {
    @apply bg-black;
  }
}