Piccalilli supports Black Lives Matter. Code is always political.

Solution: Heading Keyline

Front-End Challenges Club - Challenge #007

This is the solution for Challenge #007.

For a change, this solution is short and sweet. It’s a great example of how modern CSS layout makes our lives easier and importantly, makes our front-ends more resilient.

This solution has the following code files:

  • index.html
  • css/global.css

You can see a live demo or download a complete version of what we’re making in this solution, here.

HTML permalink

As always, let’s start with a nice HTML shell. Open up your index.html file and add the following:

Code language
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Front-End Challenges Club - 007</title>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/modern-css-reset/dist/reset.min.css"
/>

<link rel="stylesheet" href="/css/global.css" />
<link
href="https://fonts.googleapis.com/css2?family=Scope+One&display=swap"
rel="stylesheet"
/>

</head>
<body></body>
</html>

This is our core structure and as you can see, it’s pretty simple. We’re pulling in our CSS, along with a CDN version of my modern reset that I use.

Add the following HTML between the <body> tags:

Code language
HTML
<h1 class="keyline">Keylines look dope</h1>

This is a good ol’ heading with our “keyline” utility attached to it. We make “keyline” a utility rather than target the <h1> directly because we will probably want to apply it to a multitude of elements, so we want to prevent restriction as much as possible.

For now, this is our HTML sorted. Let’s make it look dope.

CSS permalink

Let’s start our CSS by adding some custom properties. Add the following to global.css:

Code language
CSS
:root {
--color-dark: #1c2334;
--color-light: #fcf3e1;
--color-primary: #e9b44c;
--metric-keyline-gap: 1rem;
}

These are the same as the challenge, but I’ve added --metric-keyline-gap to control the amount of space that we have between the keyline and the text.

After the custom properties, add the following to your CSS:

Code language
CSS
body {
display: grid;
place-items: center;
color: var(--color-dark);
background: var(--color-light);
font-family: 'Scope One', serif;
padding: 4rem 1.5rem;
}

All we’re doing here is setting our global styles right on the body itself. Everything else will inherit. We’re using the classic grid trick of place-items: center because our body is already 100vh high, thanks to the reset.

After that CSS, add the following:

Code language
CSS
.keyline {
font-weight: 400;
text-transform: uppercase;
text-align: center;
line-height: 1.2;
display: grid;
grid-template-columns: 1fr auto 1fr;
grid-gap: var(--metric-keyline-gap);
align-items: center;
width: 100%;
}

.keyline::before,
.keyline::after
{
content: '';
height: 2px;
background: var(--color-primary);
transform: translateY(-0.1em);
}

This is all the CSS we need for this utility, so lets break it down to understand what is happening:

First of all, we are setting the typography rules, such as removing the default bold weight of headings and squashing down the line-height. We’re also setting text-transform: uppercase, but that could be removed, per taste.

Next up, we use CSS Grid to create a 3 column grid. The outer columns are set to use 1fr which means each one will take up exactly one part of the available remaining space. The middle column—which houses our text—is set to auto. This means that by default, it will take the content width and not grow any further than that.

Following the grid rule, we set the gap size and then force it to fill its parent horizontally and align child items in the center.

We then add two pseudo-elements, ::before and ::after. These are our keyline elements, so we add some pretty standard block styling to give them that appearance. It’s worth noting that because we are using backgrounds, in Windows High Contrast mode, these won’t show. This is an enhancement at best, so the decoration not showing isn’t the end of the world.

With all of that done, this solution is finished…or is it?

Improving content flow permalink

This CSS works great for a short heading, but if we add lots of content, it looks pretty rubbish.

Keyline utility with new content that reads: “Keylines look dope but only if there isn’t loads of content where it starts to look a bit rubbish”

You might initially think “this is a job for minmax(). By design, this will try to create a size between the set minimum and maximum values. Perfect, right? Unfortunately not, because our pseudo-elements are set to be 1fr, which means that available space is up for the taking, so the minmax() function will return the largest value where it can. This leaves an odd looking effect with too much space.

The solution here is to add another inner element. I’ve chosen a span, so replace your <h1 class="keyline"> with this:

Code language
HTML
<h1 class="keyline">
<span>Keylines look dope</span>
</h1>

I’m very much of the opinion that if adding an extra HTML element helps you to come up with a simple and resilient solution, then do it. It’s all about balance and pragmatism. In this particular context, we’re only adding a span, which I think is all good.

Let’s add this CSS too:

Code language
CSS
.keyline > * {
max-width: 35ch;
}

What this does is pick up direct children of the keyline utility and limit the width of them to 35ch which is 35 times the size of the 0 character in the rendered font. These units, among others are really useful, so I strongly recommend that you read this article.

If you add loads of content, this limit will act as a lock and because the content of the keyline is set to auto in the main grid, it will only grow as large as this locked value, but importantly, scale until it hits this value.

With that, we are now definitely done!

Wrapping up permalink

I really hope you’ve enjoyed this tutorial. You can grab a zip of the final code that I wrote and also see a live version too. I made it all contenteditable for the demos, so go ahead and add more content to see how that lock helps things.

My favourite attempt for this challenge was by James Bateson. James’ attempt was pretty much spot on with this solution, so nice work, James.

This is also the last challenge for a long while now. You can read more about why that is here.

Until the next time, take it easy 👋