Learn Eleventy

Lesson 23: Styling global blocks

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:

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

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

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

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

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

.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

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:

.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
		&[data-state='active'],
		&[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:

.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

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:

@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

Wrapping up

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.


Lesson 22: Global CSS and design tokens Lesson 24: Styling the skip link