Lesson 23 - Styling global blocks

Learn Eleventy From Scratch
Front-End Build

The site header, navigation and site footer appear on every page, so let’s get them styled up.

We’re going to style up the site header, site footer and primary navigation in this lesson. But before we dig into writing some CSS, we need to make some adjustments to our base layout.

You might have noticed that there’s a fancy dotted border/shadow on the home page now. Well, this is fine, but it also causes some horizontal overflow issues in certain environments. In order to fix that, we need to add a site wrap to hide overflow-x.

You might be thinking “just add that to the body or html”, but in some browsers, it doesn’t work quite how you’d expect it to. So we’re going to play it safe and wrap the entire site instead.

Open up eleventy-from-scratch/src/_includes/layouts/base.html and delete everything inside of the <body>.

Replace it with the following:

Code language
<div class="site-wrap">
  {% include "partials/site-head.html" %}

  <main tabindex="-1" id="main-content">
    {% block content %}{% endblock %}

  <footer role="contentinfo" class="site-foot">
    <div class="wrapper">
      <p>This is a made up agency for the course, <a href="https://piccalil.li/course/learn-eleventy-from-scratch/">“Learn Eleventy From Scratch”</a>.</p>

We already added the CSS for this in the last lesson, so we can move straight on to the next bit.

Styling the site header and navigation permalink

Create a new file in your blocks folder called _site-head.scss and add the following to it:

Code language
.site-head {
  padding: get-size('600') 0;

  &__inner {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: center;

  &__brand {
    flex-shrink: 0;
    margin-inline-end: get-size('600'); // Prevents nav bunching up to the logo

    // Optical adjustment to account for the offset the sunken 3s create
    transform: translateY(0.25rem);

    svg {
      width: 100px;

  &__nav {
    padding: get-size('300') 0;

  @include media-query('md') {
    &__brand {
      svg {
        width: 160px;

When you scrape aside the visual CSS in this block, the real important content is in the &__inner element.

We use display: flex to flexibly layout its direct children. If there’s room and because the default layout of flex is row, the direct children: the logo and navigation, will sit side-by-side. We also use justify-content: space-between to push those elements away from each other, where there’s space.

Lastly, by using flex-wrap: wrap, if there’s not enough room for the logo and navigation to sit side-by-side, they’ll stack on top of each other instead.

If you’ve not used Sass, you might be wondering what & means when it’s nested. This is called the parent selector. This gives us access to the parent’s selector when we’re nested, so we don’t have to keep repeating ourselves. In the context of this block, the & means .site-head, so when the CSS has been processed, &__inner will render as .site-head__inner.

Pro tip: we use flex-shrink: 0 on the &__brand element. This prevents it getting squashed when space gets a bit tight. By design, flexbox will try to be flexible (no surprises there). So when space gets reduced, it will continue to try and sit items side-by-side, by default.

When we use flex-shrink: 0, we’re effectively stopping that element from being able to shrink in these scenarios.

You might have also noticed that this element uses margin-inline-end, too. This is called a logical property.

Styling the navigation permalink

Now we have the site header CSS, let’s add the navigation CSS.

In your blocks folder again, create another new file called _nav.scss and add the following to it:

Code language
.nav {
  line-height: 1;
  font-weight: 900;
  margin-top: -#{get-size('400')};
  margin-inline-start: -#{get-size('400')};

  &__list {
    display: flex;
    flex-wrap: wrap;

    > * {
      padding-top: get-size('400');
      padding-inline-start: get-size('400');

  a {
    text-decoration: none;
    display: block;
    position: relative;

    // Adds the fake border to active state items
    &[aria-current='page'] {
      &:before {
        content: '';
        display: block;
        width: 100%;
        height: 0.25rem;
        position: absolute;
        top: 100%;
        left: 0;
        margin-top: 0.25rem;
        background: get-color('quinary-shade');

This block consists mostly of composition code to make the navigation behave responsively. We achieve this with similar principles to the site head, by letting flexbox wrap. The difference here is that we use a negative vertical and horizontal margin, mixed with a positive vertical and horizontal padding to auto-flow items.

This means that when there’s room, the navigation items will align side-by-side, but when room starts running out, items will drop-off onto a new line. This means that on small screens, like mobiles, there will probably be a couple of rows of navigation links, but on wider screens, like laptops, there will be a single row instead.

This sort of CSS gives hints to the browser by defining some base rules. The browser is much more qualified to make layout decisions than we are—especially based on the exact user situation. So if we let it do its thing, within reason, we can achieve some seriously solid layouts, with tiny amounts of code.

The last thing to shine a light on in this block is the highlight (I’ll show myself out). Remember when we built the navigation earlier in the course and we added active states to navigation items? Well, on line 23 is the CSS that powers that.

We use a pseudo-element to provide an underline to the active element. Lovely stuff.

Create one more new file in your blocks folder called _site-foot.scss and add the following CSS to it:

Code language
.site-foot {
  padding: get-size('500') 0 get-size('700') 0;
  text-align: center;

This is CUBE CSS in a nutshell. Most of the footer has already been accounted for with global styles and utilities, so all we need to do is add a bit of spacing and tell it to centre the text.

Wiring it all up permalink

We’ve got 3 new blocks here, so let’s add them to the critical CSS. Open up eleventy-from-scratch/src/scss/critical.scss and around line 75, add the following:

Code language
@import 'blocks/site-foot';
@import 'blocks/site-head';
@import 'blocks/nav';

Now, when you open your browser at http://localhost:8080, it should look a bit like this:

A nicely styled site head and navigation

Notice how the horizontal scrollbar has now gone

Wrapping up permalink

These are really key elements to the overall design of the site and they are now done. Let’s tidy that up now by building out the skip link.


Next up: Lesson 24 - Styling the skip link

Skip links are really handy for screen reader and keyboard users, so let’s style ours up, along with the button block.

Get started

Help! My version of this lesson isn’t working.

Don’t panic, you can download the working project here! Once they are downloaded: replace your project with these files and run npm install. You can read more information here.

Download project files

Hello, I’m Andy and I’ll help you build fast, accessible websites & design systems.

I’m a freelance CSS and design systems consultant, based in the UK. I specialise in design systems and creative web design, such as landing pages and campaign work.

I’m currently helping Google by refactoring the CSS and creating a design system for web.dev, but I have availability for projects such as small websites, landing pages and consultancy. I will have full availability for larger projects in January 2022.

Hire me