Skip to content

Styled Drop Cap Behind Text

I was thinking the other day about the recent web design trend of putting large letters behind a block of text. Kind of like a drop cap but not quite. If you want to skip to the tiny example I made, you can check out this codepen. Otherwise, I'll show you step by step my thought process.

  • Make some markup
  • Get the first letter with javascript
  • Create a new element and add the first letter to it
  • Style everything.

HTML

Since this was a kind of tiny demo, I didn't want to make anything big. Mainly just one piece of text with a container.

<main>
  <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Deserunt aliquid adipisci, ad, incidunt aliquam a necessitatibus, magni minus iusto numquam atque eligendi dignissimos eius delectus sapiente consequatur commodi. Voluptatem, officia?</p>
</main>

JS

I want this style to be as accessible as possible which is why I'm going to use JS to create the "big letter". If the javascript isn't loaded for some reason, that's ok. The design won't be 100% correct, but the text will still make sense. So, here we go!

// get the container element
const main = document.querySelector('main');
// find the text
const p = main.querySelector('p');
// get just the first letter
const firstLetter = p.innerText.substring(0, 1);

// create a new span
const span = document.createElement('span');
// add it to the container
main.appendChild(span);
// set the text to be just the first letter
span.innerText = firstLetter;
// hide the "text" from screen readers
span.setAttribute('aria-hidden', 'true');

Now if javascript is running, I've got this markup

<main>
  <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Deserunt aliquid adipisci, ad, incidunt aliquam a necessitatibus, magni minus iusto numquam atque eligendi dignissimos eius delectus sapiente consequatur commodi. Voluptatem, officia?</p>
  <span aria-hidden="true">L</span>
</main>

You might be wondering about the last line - span.setAttribute('aria-hidden', 'true');. This will prevent screen readers from acknowledging the letter so they won't just read "L". If I didn't do this it might cause undue confusion to people using the screen reader.

CSS

Last, I want to style everything. I want to make sure that the main text is readable, but the "big letter" is still visible as a design element.

The way I want to do this is by showing just the outline of the letter. But not so fast, let's make sure everything is more or less where I want.

body {
  margin: 0;
}

main {
  /* 
  give the background a light tan color. 
  pure white can be hard to read for some people
  */
  background-color: #faebd70f;
  font-size: 1.2em;
  font-family: Roboto;
  max-width: 25em;
  margin: 0 auto;
  padding: 10em 20em;
  position: relative;
}

Next, I want to set the position and size of the span. The great thing about css is that if the span doesn't exist, the styles simply won't apply and the page won't break.

main span {
  position: absolute;
  top: 0;
  left: 0.6em;
  font-size: 34em;
  font-family: sans-serif;
  line-height: 0.7;
}

Now, at this point, there's a big problem. All the text is black. Well that's fixable. Let's make the span a light blue to complement the tan background by adding color: #87cefa57;.

main span {
  color: #87cefa57;
  position: absolute;
  top: 0;
  left: 0.6em;
  font-size: 34em;
  font-family: sans-serif;
  line-height: 0.7;
}

Now, there's another problem. Because the span has position: absolute; it wants to stack on top of the main text. You might think to fix this by giving the text a z-index above 1, but what I found works better is to give the span z-index: -1 which forces it back. Then you can also make the text go in front if like

main p {
  z-index: 10;
}

main span {
  color: #87cefa57;
  position: absolute;
  top: 0;
  left: 0.6em;
  font-size: 34em;
  font-family: sans-serif;
  line-height: 0.7;
  z-index: -1;
}

Now, we're getting somewhere. Last, for browsers that support it, I want to just use the outline of the letter. To do that I'm using some -webkit-text properties.

  • -webkit-text-fill-color (what color should the text be?)
  • -webkit-text-stroke-width (Make a "border" around the text)
  • -webkit-text-stroke-color (What color should the "border" be?)
main span {
  color: #87cefa57;
  position: absolute;
  top: 0;
  left: 0.6em;
  font-size: 34em;
  font-family: sans-serif;
  line-height: 0.7;
  z-index: -1;
  -webkit-text-fill-color: transparent;
  -webkit-text-stroke-width: 1px;
  -webkit-text-stroke-color: #87cefa57;
}

What's nice is that if the browser doesn't support those properties, the text will still appear as the light blue.

Conclusion

This was a fun little experiment and only took a few minutes to put together. I'm sure there are some style improvements that could be made, but just as an exploration of how to do it, I think it's useful and I hope you think so too.