Injecting a Line Break

Avatar of Chris Coyier
Chris Coyier on (Updated on )

UGURUS offers elite coaching and mentorship for agency owners looking to grow. Start with the free Agency Accelerator today.

I had a little situation where I had a header with a span in it, and I wanted to make sure to put a line break before the span. For the record, there really isn’t anything wrong with just chucking a <br> tag before it (and in fact the ability to show/hide that is very useful). But… it always feels a little weird to have to use HTML to achieve a layout thing.

So let’s take a journey. A journey in which we say “But…” a lot.

<h1 class="one">

  Break right after this

  <!-- <br> could go here, but can we do it with CSS? -->

  <span>
    and before this
  </span>

</h1>

A block level element would do it

Rather than a <span>, we could use a <div>, and we’ll get that break just by virtue of the div being a block-level element.

But we’re using a span on purpose, because of the design. The text after the break should be inline/inline-block, because it’s going to have a background and padding and such.

You can insert line breaks via pseudo element

It’s easy:

h1 span::before {
  content: "\A";
}

But… the <span> is an inline element. The line break won’t do anything! Just like a real line break won’t do anything.

We can force that line break to work by making white space meaningful…

h1.two span::before {
  content: "\A";
  white-space: pre;
}

That actually works. But… because of the padding and background, it leaves a little chunk of that behind when the line breaks:

We could fix the awkward-left-edge-hugging on by using box-decoration-break: clone;, but… that just leaves a bigger chunk up top:

box-decoration-break is great for some issues, but not this one.

If we made the span inline-block, the break would happen within that block, which isn’t what we want either:

Making the pseudo element block-level and leaving the span alone doesn’t do the trick either:

You could get a little weird and inject the actual text with a pseudo element

This was Aaron Bushnell’s idea. The trick here is to make the span block level, but then inject the text with a pseudo element and style it as an inline element.

h1 span {
  display: block;
}
h1 span::before {
  content: attr(data-text);
  background: black;
  padding: 1px 8px;
}
It works! But…

I’ve long been a fan of pseudo-element trickery, but this feels slightly dangerous in that you may be hurting accessibility. I think some screen readers read pseudo-elements, but I don’t think all, nor are they supposed to. Not to mention you can’t copy and paste all the text this way. At least the text is still maintained entirely in the HTML!

Exploiting table layout

My favorite idea came from Thierry Koblentz. Just make the span display: table; and you’re done. It’s not tabular data of course, but that doesn’t matter. The fact you can force table layout from CSS is all about exploiting the unique layout properties of table layout — not semantics.

h1 span {
  display: table;
}

Live Demos

Including one where we just use a <br>, which is fine.

See the Pen Attempting a line break before and inline-block within a header by Chris Coyier (@chriscoyier) on CodePen.