Hidden Brain Podcast Logo in CSS

November 25, 2021

Hey, so I’m just sitting here in the living room with my family on Thanksgiving. Everyone is either watching TV or reading a book, except for me.

I could be doing a million different things right now. What did my blond brain wind up deciding to do? I’ve got my laptop fired up and CodePen open with nothing but time to spare. So, of course I spent my time recreating the logo for the Hidden Brain podcast.

Here’s what I did…

The HTML

Gotta keep this as clean and accessible as possible, so:

<div class="logo">
  <h1>
    Hidd<span>e</span>n
    <br>
    Br<span>a</span>in
  </h1>
</div>

That <div> isn’t really necessary. Just a way to scope the styles in case I ever decide to drop this somewhere. Otherwise, all we have is an <h1> and a couple of classless <span> elements.

That line break? I couldn’t find a great way to break the words into separate lines without it so there you have it.

Basic styles

The logo is white and usually displayed against a blue background, so we can start with that.

.logo {
  --color-bkg: #22315c;
  --color-text: #fff;

  background-color: var(--color-bkg);
  display: grid;
  height: 100vh;
  place-items: center;
}
.logo h1 {
  color: var(--color-text);
}

OK, so our .logo container takes up the full screen and centers the heading, which is white. I created variables for the background color and text so we can use them again later.

The logo is in all caps which calls for text-transform. As far as the font is concerned, I couldn’t find a perfect one-to-one match. I decided Roboto was pretty darn close, so I merely fetched it from Google Fonts.

.logo h1 {
  color: var(--color-text);
  font-family: Roboto, sans-serif;
  text-transform: uppercase;
}

The font size is just a guess. But whatever it is, we probably should use relative units so it scales and such, like when zooming. I’m using a small line-height value to decrease the vertical space between the words a smidge. We also ought to center-align the actual text while we’re at it.

.logo h1 {
  /* Same as before */
  font-size: 6rem;
  line-height: 0.85;
  text-align: center;
}

Believe it or not, that’s largely it for global styling. Let’s focus on the spans next because that’s where the tricks are.

Styling the spans

Looking at the logo, the letter “E” in “hidden” and letter “A” in “brain” are inverted, i.e. they are blue against a white background. I thought this would be a simple case defining a background color and setting the text color to white, like this:

/* No bueno */
.logo span {
  background-color: var(--color-text);
  color: var(--color-bkg);
}

The problem is that the background goes way outside the lettering.

Darnit. That sent my mind down a windy path with mask properties. And to be totally frank, I’m terrible with CSS masking. It’s not that I have no idea what it does; it’s more that the properties are difficult to grok. But I knew it was probably the right way to go.

CSS masks need a couple of things: a mask-image and a mask-size. The idea is that the span background sorta draws around the shape of the mask image and leaves the shape’s fill color alone.

But each span needs a different mask image because the shapes for “E” and “A” are different. I wound up creating two SVGs real quick-like. Can’t really see them since they’re white, but here’s the E and here’s the A if you want them.

.logo {
  /* Same as before */
  --letter-mask: url(letter-e.svg);
}
.logo span {
  background-color: var(--color-text);
  mask-repeat: no-repeat;
  mask-size: contain;
}
.logo span:nth-child(3) {
  --letter-mask: url(letter-a.svg);
}

What’s up with that weird :nth-child(3) selector? Turns out :nth-child() counts any element when it counts spans?!

OK, so here’s how my thinking:

  • The spans each have the same background-color and we have a variable we can use for it.
  • The mask-repeat and mask-size properties are declared on the span because they apply to both letters.
  • The mask-image is set as a variable that points to the letter E shape. Then the variable is redefined as the letter A when we select the second span using the span:nth-child(3) selector.
  • Mask images repeat by default, just like background images. So, that’s why we’re declaring mask-repeat: no-repeat.

We’re getting closer!

The rest is fine-tuning

I ain’t no fan of magic numbers but know some numeric values have to be to get things just right. And a logo seems like a fine situation for that sort of thing. I didn’t use a lot of them though.

First, the size of the mass are a bit on the big side reduce the line height of the spans to reign them in a bit.

.logo span {
  /* Same as before */
  line-height: 0.55;
}

That works extremely well for the E, but the A needs a little more tweaking. I decided padding would be helpful:

span:nth-child(3) {
  /* Same as before */
  padding: 0.4rem;
}

Nice! Now that both letters are the right size and everything, the only thing is to adjust the space between them and the letters around them. If you look closely at the logo, the negative space between the spans and other letters is what forms the shapes of the letters. So, let’s pull those closer together.

margin-inline: .625rem; -1.5625rem; /* 10px -25px */

I made those into variables, but that’s not really necessary.

Here’s the final demo one more time

We’re all done!