The Underscores (_s) theme with Sass and Gulp Part 4: building the header

Untitled Document

==================================================================

On this page:

  1. Style the default header.
  2. Add an optional image function.
  3. Show the header image only on the front page.
  4. Add an optional logo to the custom header.
  5. Fix responsive problems in the header.

==================================================================

17. Style the default header

Github repo branch: part4_17

From here on forward we'll apply styles and functionality to the theme to make it look and behave the way we want to. And I like to do this by starting at the top and working my way down module by module, so that's how the course is laid out. Each part focuses on a separate module. We'll style and add functionality to it until it works the way it's supposed to then we move on to the next module. In this part we'll focus on the header.

First we take a look at he header.php

<?php
  /**
  * The header for our theme
  *
  * This is the template that displays all of the <head> section and everything up until <div id="content">
  *
  * @link https://developer.wordpress.org/themes/basics/template-files/#template-partials
  *
  * @package Pre_Underscores
  */
?>
  <!doctype html>
  <html <?php language_attributes(); ?>>
  <head>
  <meta charset="<?php bloginfo( 'charset' ); ?>">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="profile" href="http://gmpg.org/xfn/11">
 <?php wp_head(); ?>
  </head>
<body <?php body_class(); ?>>
  <div id="page" class="site">
  <a class="skip-link screen-reader-text" href="#content"><?php esc_html_e( 'Skip to content', 'pre_underscores' ); ?></a>
 <header id="masthead" class="site-header">
  <div class="site-branding">
  <?php
  the_custom_logo();
  if ( is_front_page() && is_home() ) : ?>
  <h1 class="site-title"><a href="<?php echo esc_url( home_url( '/' ) ); ?>" rel="home"><?php bloginfo( 'name' ); ?></a></h1>
  <?php else : ?>
  <p class="site-title"><a href="<?php echo esc_url( home_url( '/' ) ); ?>" rel="home"><?php bloginfo( 'name' ); ?></a></p>
  <?php
  endif;
 $description = get_bloginfo( 'description', 'display' );
  if ( $description || is_customize_preview() ) : ?>
  <p class="site-description"><?php echo $description; /* WPCS: xss ok. */ ?></p>
  <?php
  endif; ?>
  </div><!-- .site-branding -->
 <nav id="site-navigation" class="main-navigation">
  <button class="menu-toggle" aria-controls="primary-menu" aria-expanded="false"><?php esc_html_e( 'Primary Menu', 'pre_underscores' ); ?></button>
  <?php
  wp_nav_menu( array(
  'theme_location' => 'menu-1',
  'menu_id'        => 'primary-menu',
  ) );
  ?>
  </nav><!-- #site-navigation -->
  </header><!-- #masthead -->
 <div id="content" class="site-content">
  • Within the body element we have a div with the class site that also wraps around everything. And then directly after we have a link. This is the skip to content link. It's required for accessibility purposes. This is . If I go back to my site and hit tab once a link opens up at the very top that says skip to content and if I hit that link I skip down to the main content in the page. That way someone using a screen reading browser or someone who's navigating through the site using a keyboard don't have to tab through the entire menu and everything to get to the content. You can leave this one alone. You don't have to apply styles to it or anything it just works out of the box with underscores
  • Heeder.php is marked up using a header element and has the class 'site-header'. Inside the header we have two elements. The div with the class site-branding. This contains the site title and site description. And then a nav with the class main-navigation. This contains the navigation.
  • nside site branding the site title is displayed conditionally depending on where you are. So if you're on the front page it's displayed as an <h1> title because it's the main element. If you're anywhere else on the site it's displayed as a paragraph. And that means when we style the site title we have to target the class site title not an <h1> one.
  • We are going to apply a background color to the entire header, then restyle the site title and tagline and then finally float the site title and tagline to the left and the menu to the right using Flexbox.

17.1 Change site.scss

Inside the sass/site/_site.scss file I place header directly after the global layout.

/*--------------------------------------------------------------
  ## Global layouts
  --------------------------------------------------------------*/
  @import "../layout/global";
/*--------------------------------------------------------------
  ## Header
  --------------------------------------------------------------*/
  @import "header/header";
/*--------------------------------------------------------------
  ## Posts and pages
  --------------------------------------------------------------*/
  @import "primary/posts-and-pages";
/*--------------------------------------------------------------
  ## Comments
  --------------------------------------------------------------*/
  @import "primary/comments";;
  

17.2 In the sass/site place a new folder

Under the sass/site folder we place a new folder called 'header' with a file inside it called _header.scss and this is where we'll place all our styles.


  .site-header {
  position: relative;
  padding: 1em;
  font-family: $font__sans;
  color: #fff;
  background-color: $color__skin;
  
  @media screen and (min-width: $query__small) {
  padding: 1em 2em;
  }
  }
.site-branding {
  min-height: 65px;
  }
.site-title {
  margin: 0;
  padding: 0;
  font-size: 1.6em;
  font-weight: 900;
  line-height: 1em;
  
  a {
  color: white;
  text-decoration: none;
  
  &:hover,
  &:focus {
  text-decoration: underline;
  }
  }
  }
.site-description {
  margin: 0;
  font-size: .9em;
  font-style: italic;
  font-weight: 100;
  }

  

17.3 Add background color

Place the background color in sass/variables-sites/_colors.scss

$color__skin: #002254; //header etc

Now go back to the browser and you'll see the colored header and some padding on the left and the right hand side and the padding will change when we reduce the width of the screen. The header looks much nicer with this tight display of the site title and tagline.

The only thing we need to do to finalize this is to make sure the menu falls to the right hand side. And we can do that using Flexbox. So all I have to do is find out which container holds both the site branding and the navigation. That is site header.

17.4 Add flex to the header

In _header.scss I'am going to place the following lines:

@media screen and (min-width: $query__medium) {
.site-header {
display: flex;
justify-content: space-between;
}

.site-branding {
width: 35%;
}

.site-navigation {
width: 55%;
}
}

Go back to the browser and change the width of the screen to see flex in action. The menu positions at the right in wider screens and under the title in smaller screens. Awesome!

==================================================================

18. Add an optional image function

Github repo branch: part4_18

If your design calls for it, you can add customer header image functionality to your theme. That means the site admin can into the customizer and add a custom header image and that image will be displayed however you want it to display in the context of theme. There is a little issue however: if you are using Browsersync, like I am, and you go to the customizer, you'll notice it's not working properly. That's because of a cross-domain issue that happens when we're using Browsersync so if you want to gain full access to the customizer, you actually have to open a separate tab and then just go directly to the site outside of Browsersync.

Inside the customizer, I currently have an active option called Header Image. When I open it, you'll see the header image will be cropped to 1000 by 250 pixels which is too small for my needs. But even if I do upload an image, it will not work in my site because it's not being displayed anywhere. So in this movie we'll do three things.

  1. First, we'll change the settings so that we get the right size image.
  2. Then we'll hook the image into our theme so it's actually being displayed.
  3. And then we'll apply the necessary styling to make it work the way we want to

When we looked at functions.php earlier in the course, you may remember at the very bottom here, you may remember that towards the bottom of the file you had all these require statements that pointed at the inc folder. First required file is inc/custom-header.

**
* Implement the Custom Header feature.
*/
require get_template_directory() . '/inc/custom-header.php';

This is where all the custom header information is defined.

/**
* Set up the WordPress core custom header feature.
*
* @uses pre_underscores_header_style()
*/
function pre_underscores_custom_header_setup() {
add_theme_support( 'custom-header', apply_filters( 'pre_underscores_custom_header_args', array(
'default-image'          => '',
'default-text-color'     => '000000',
'width'                  => 1000,
'height'                 => 250,
'flex-height'            => true,
'wp-head-callback'       => 'pre_underscores_header_style',
) ) );
}
add_action( 'after_setup_theme', 'pre_underscores_custom_header_setup' 

First we add theme support for the custom header, then we set up an array of settings for the custom header. So here you can provide a link to a default image if you want to (for instance: get_parent_theme_file_uri( '/assets/images/header.jpg' )). You can set a default text color, right now it's black so I'm going to set this to white, that's the text color that being displayed currently on the front end. Then you set the width and height of the image you want to display and in my case that would be 2000 by 850 pixels. If you want the person who uploads the image to be able to define a specific height or width, you can choose to set flex-height or flex-width. This impacts the cropping tool.

This impacts the cropping tool. I'm going to leave that at 'true' for flex-height. And then this last callback we're just going to ignore. Saving this will change the features inside the customizer so if I reload the customizer you'll see under header image we now say 2000 by 850 pixels but if I add an image from my computer, let's say this one, upload it, click select and crop, because I have flex-height, I can now crop to whatever height I want.

And then click crop image, but doing so changes nothing. Save and publish, close the customizer, no image appears. That's because so far, we haven't added the image into our theme anywhere. The cool thing is, Underscore actually ships with the necessary code, you just have to copy it and paste it in where you want it to appear. That code is found at the very top of custom-header.php. Right here, it even says, you can add an optional custom header image to header.php like so and then you just have the code here. So let's copy out this code in its entirety.

<figure class="header-image">
 <?php the_header_image_tag(); ?>
 </figure><!-- .header-image -->

the the_header_image_tag() exists in the wp-includes.theme.php file. Througt this function there is is a if else statement that checks the existance of a header image. If there is no header image, the functions returns an empty string

I put it all in a <figure> element with a class of 'header-image', so that I van style it later.

So if I go to the sass/elements/_elements.cscc I should find .figure in there somewhere. I am going to just set the margin to 0 because I never want to have that margin on any figures on my site.

figure {
margin: 0 0; /* Extra wide images within figure tags don't overflow the content area. */
}

That should immediately remove that space and it did. The next thing I want to do is make sure the image is displayed as a block level element because you see right now we have that little weird space under the image. That's because the image is currently in line so I just go down here and say display block you'll see this space goes away.

figure.header-image img {
display: block;
}

<p>If you go to your browser you will see that the margins under and above our header image are gone. Great! </p>

==================================================================

19. Show the header image only on the front page

Github repo branch: part4_19

A very common thing I see now a days, on themes and on sites in general, is the home page will have a giant header image and then if you go anywhere else you just see the header. Right now, no matter where I go in my site, I'll always have that giant header at the top, so how do I go about changing that so I only display the header image on the front page and nowhere else. Here we can use one of two conditional statements.

  1. is_front_page. This conditional asks are we on the main URL for the site right now, so on the root URL of the site. If we are, then this function passes true. If not, it passes false.
  2. is_home This function tests whether we are currently on the blog home page, so that means the index page. If you go into WordPress settings and you change what is displayed on the front page, is_home will return true only when you're on the blog index. So if you relegate the blog index to a separate page, this returns true when you're on that blog index. So is_home is not necessarily going to return true even though you're on the home page. Where as, is_front_page will aways return true if you're on the home page.

That means, if we want to display the header only on the front page, we use this function, is_front_page. We can do this by slightly augmenting the existing markup for header.php. Here we already have a conditional statement, the_header_image_tag(), meaning there is a header image available and then I can just extend that.

So in header.php change:


 <figure class="header-image">
 <?php the_header_image_tag(); ?>
 </figure><!-- .header-image -->
 

To:

<?php if ( is_front_page()  ) : ?>
 <figure class="header-image">
 <?php the_header_image_tag(); ?>
 </figure><!-- .header-image -->
 <?php endif;  //end frontpage check ?>

Now go back to the site. On the front page we see the header image. Go to any other page, header image disappears. Back to the front page and the header reappears. Magic!

==================================================================

20. Add an optional logo to the custom header

Github repo branch: part4_20

In addition to a custom header image, WordPress also allows you to add a custom logo feature to your theme. To do that, you have to first activate it on the back end, then tell the theme where you want it to display the custom logo, and finally, add styles to it. The custom logo relies on the Customizer, so here, once again, we have to open the site in a separate tab where we're not using Browsersync. Then we get full access to the Customizer. And right now, since the feature is not available, you can see if I go to Site Identity, I can only change the Site Title and site Tagline. Let's start by adding the functionality for a custom logo too.

We do that in functions.php. And I want to do it inside the pre_underscores_setup function right underneath the custom background setup. The feature is called in by adding theme support for custom logo. And here, just like with most other features, I can pass an array of options. In my case, I want to define a width to 90 pixels, a height to 90 pixels.

// Add theme support for Custom Logo
add_theme_support( 'custom-logo', array(
'width' => 90,
'height' => 90,
'flex-width' => true,
));

And once I made those changes, I can reload the Customizer, go to Site Identity, and now you'll see we have a new feature here called Logo. From here I can select a logo. So I'll just pick this one from the existing images from the theme unit test data, click Select and pick a logo from your own image library (or just make a sample logo yourself.

Then I can change to crop if I want to. I'm just going to click Crop Image. And now the custom logo is added to the site. However, it's not being displayed on the site because I haven't told the theme where I want it to be displayed yet. So I'll just click Save & Publish, close the Customizer, and go back to the Browsersync window. Then I'll go to header.php and find where I want the logo to appear. So scrolling down, I want it to appear inside site branding, before the site title and tagline. So I'll add in php. And then, to display the custom logo, I simply call the_custom_logo.

<header id="masthead" class="site-header" role="banner">
  <div class="site-branding">
  
  <?php the_custom_logo(); ?>
  
  <?php
  if ( is_front_page() && is_home() ) : ?>
  <h1 class="site-title"><a href="<?php echo esc_url( home_url( '/' ) ); ?>" rel="home"><?php bloginfo( 'name' ); ?></a></h1>
  <?php else : ?>
  <p class="site-title"><a href="<?php echo esc_url( home_url( '/' ) ); ?>" rel="home"><?php bloginfo( 'name' ); ?></a></p>
  <?php
  endif;
 $description = get_bloginfo( 'description', 'display' );
  if ( $description || is_customize_preview() ) : ?>
  <p class="site-description"><?php echo $description; /* WPCS: xss ok. */ ?></p>
  <?php
  endif; ?>
  
  </div><!-- .site-branding -->
The site header code with the custom logo placed

And now, when I go back to the browser, the logo appears. And the cool thing is, this logo is already wrapped in a link. So when we look at the markup, you'll see here we have an image, and the image is wrapped inside a link that points to the home page. That link has a class custom logo link, and now we can use that class to target the logo with CSS. We're still in the header, so I'll go to the sass file sass/site/header/_header.scss. Here I'm working inside the site branding section. So I'll add some space inside site branding. Then I'll call for custom-logo-link. Here I first want to add some styles to the image, so I'll nest an image inside and say display: block;, 'cause it's an image and I want it to display as a block-level element. I will set the height to 65 pixels. This is the same as the min height for the site branding. And you'll see in a second why that matters. I'll set the width to auto just in case something goes wrong and the image will be stretched. (see code 4.20.3)

.custom-logo-link {
	margin-right: 1em;
	img {
		display: block;
		height: 65px;
		width: auto;
	}
}
Code4.20.3

Then I'll save everything, go back to the browser, and take a look at what happened. And all that happened right now is the image got reduced in size. The next step is to change the layout. So here's what I want to happen. The image should appear on the left-hand side, then the site title and tagline should float up next to it. And if we have both a site title and tagline, they should be centered according to the height of the image. If we only have a site title, it should be still center. So that means we need to use Flex Box. That's the easiest way of doing it. However, we can simply apply flex to site branding, because we have three elements. We have the image, then we have the site title, and then we have the site description. So to make this work, I need to wrap site title and site description in a container so that I can put the image next to that container. And then within that container I'll have site title and site description.

Back in header.php, I'll wrap that container around all of this content. So directly after the custom logo, I'll put in a new container, give it to class site-branding_text. Then in that container, right here above the end of site-branding, now these are two elements.(see code 4.20.4)

<header id="masthead" class="site-header" role="banner">
  <div class="site-branding">
  
  <?php the_custom_logo(); ?>
  <div class="site-branding__text">
  <?php
  if ( is_front_page() && is_home() ) : ?>
  <h1 class="site-title"><a href="<?php echo esc_url( home_url( '/' ) ); ?>" rel="home"><?php bloginfo( 'name' ); ?></a></h1>
  <?php else : ?>
  <p class="site-title"><a href="<?php echo esc_url( home_url( '/' ) ); ?>" rel="home"><?php bloginfo( 'name' ); ?></a></p>
  <?php
  endif;
 $description = get_bloginfo( 'description', 'display' );
  if ( $description || is_customize_preview() ) : ?>
  <p class="site-description"><?php echo $description; /* WPCS: xss ok. */ ?></p>
  <?php
  endif; ?>
  </div><!-- .site-branding__text -->
  </div><!-- .site-branding -->
 <nav id="site-navigation" class="main-navigation" role="navigation">
  <button class="menu-toggle" aria-controls="primary-menu" aria-expanded="false"><?php esc_html_e( 'Primary Menu', 'humescores' ); ?></button>
  <?php wp_nav_menu( array( 'theme_location' => 'primary', 'menu_id' => 'primary-menu' ) ); ?>
  </nav><!-- #site-navigation -->
  </header><!-- #masthead -->
Code4.20.4

So if I inspect that again, you'll see here we have the link, and then we have site-branding_text. And that means I can go to site-branding and set displaying flex, and it'll float up one next to the other. So, back in the styles for the header, I'll set site-branding to displaying flex. But I'm also going to give the custom-logo-link a bit of space on the right-hand side. So I'll set margin-right to 1em.(See Code4.20.5)

.custom-logo-link {
  margin-right: 1em;
  img {
  display: block;
  height: 65px;
  width: auto;
  }
  }

Code4.20.5

Save that, reload in the browser. And look at that. Now we have the logo next to the text.

Now, the last part is to make sure that the title and tagline always float in the center, vertically of this box. And I can do that by targeting site-branding_text specifically. So I'll go in here, create a new rule, site-branding_text, and set display again to flex, flex-direction to column so it's vertical, justify-content to center, and then set the height to 65 pixels. (See Code4.20.6)

.custom-logo-link {
  margin-right: 1em;
  img {
  display: block;
  height: 65px;
  width: auto;
  }
  }
.site-branding__text {
  display: flex;
  flex-direction: column;
  justify-content: center;
  height: 65px;
  }
Code4.20.6

Save that and check out what happens now. If I display the site logo, and the site title, and the tagline, it all hovers in the center like it's supposed to. If I go in and inspect this, I can now remove the site description and the title will shift down to still be centered next to the image. If I then go to the Customizer, go back to the Customizer, Site Identity, and Remove the site Logo, the Title and Tagline shift over to the left and everything looks fine. So now we have a conditional layout that will always look correct, whether we have a site title, a site tagline, or a site logo, or any combination of the three.

==================================================================

21. Fix responsive problems in the header

Github repo branch: part4_21

If you ignore the menu, and look at the rest of the header, it is now matching our designs pretty well. However, there's still a small problem we need to fix. If I got to the responsive preview, and reduce the width of the screen, you'll notice that the site branding here is getting squished. That's because right now, the entire header is a Flexbox and we haven't told the Flexbox anything about how to handle the elements within. We've just said that I want the site branding to take up 35%, and the menu to take up 55%. What's happening is, the contents within the header are wider than 55%, so the Flexbox is trying to accommodate that content, as much as possible, by equally reducing the width of both the header container, with it's full content, and the site branding container. To fix this, we need to tell the Flexbox not to shrink the site branding element. And we can do that using some basic CSS. So, first I find the site branding. Here's the media query that kicks in when we are using Flexbox. And I'll just say 'flex one', meaning it can grow in size. 'Zero', meaning it cannot shrink in size, and finally set basis to 'auto', telling Flexbox that the size of this container is whatever size the content inside it is. So, regardless of how big it is, there will always be space for the content, and it will not be reduced in size.

So in sass/site/header/_header.scss change:

.site-branding {
width: 35%;
}

Into:

.site-branding {
width: 35%;
flex: 1 0 auto;
}
Code4.20.7

Save and reload, and now you see the site branding does not change shape. But, there's still one more problem. If I reduce the width, you'll see right now the menu starts to wrap once there's not enough space for it. But I actually want the menu to drop down below the site branding when that happens. And technically I should be able to do that by simply grabbing the Flexbox container which is 'site-header', and then just setting 'flex-wrap' to 'wrap'. The problem is, when I do this, no matter how wide the screen is, the menu never jumps back on top again. Hmm, I wonder why? Well, if we look very closely at the markup here, you'll see why. If I open the header, you'll see they're actually not two elements inside the header right now, there are four. So, we have the two we know about, 'site-branding' and 'site-navigation'. But then there's two additional ones. There's a 'before' pseudo-element and an 'after' pseudo-element. Now, these are default styles and underscores and they're there for specific reasons, to clear floats. What I mean by that is, if you create a layout that puts, floats some content to the left and other content to the right, you need to clear the boxes so that you don't get overlap of content. This is the old way of doing things and it does not work well with Flexbox, especially not if you justify content. So, what we need to do is remove the clearing, specifically for the site-header.

Now, you can see in the inspector, that the clearings are sitting inside 'modules/clearings'. If I go to sass/modules/_clearings.scss we can see the clearings among them in the site-header.

.clear:before,
  .clear:after,
  .entry-content:before,
  .entry-content:after,
  .comment-content:before,
  .comment-content:after,
  .site-header:before,
  .site-header:after,
  .site-content:before,
  .site-content:after,
  .site-footer:before,
  .site-footer:after {
  @include clearfix;
  }
.clear:after,
  .entry-content:after,
  .comment-content:after,
  .site-header:after,
  .site-content:after,
  .site-footer:after {
  @include clearfix-after;
  }
  

So, I'll simply remove site-header from this list for now, and we may end up removing all of this at the end.

.clear:before,
  .clear:after,
  .entry-content:before,
  .entry-content:after,
  .comment-content:before,
  .comment-content:after,
  .site-content:before,
  .site-content:after,
  .site-footer:before,
  .site-footer:after {
  @include clearfix;
  }
.clear:after,
  .entry-content:after,
  .comment-content:after,
  .site-header:after,
  .site-content:after,
  .site-footer:after {
  @include clearfix-after;
  }
  

Save, go back, and now the wrapping should behave properly. So, on widescreens, we have the site branding on the left and the menu on the right, and as we reduce the width eventually the menus drop down. It's a subtle change, but it's something we need to do now because it will become important later on. In fact, anytime we use Flexbox and any kind of justification in Flexbox, we need to make sure the content is not being cleared with pseudo-elements, like what you saw right here.

Leave a comment