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:
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;
}
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.
But
… yeah … another boring day in the office. It’s how old web sites, once coded in a couple KB, are now Megabyte monsters requiring copious amounts of bandwidth and server farm capacity to say … well … essentially the same thing they did before but now with lots of pretty pictures and colors. :D < eyes rolling >
But, why not use div instead of span and mark it with display: inline-block?
I’ll leave the onus on you to explain how that would help ;) demo?
I’d go for this one
It doesn’t work.
With inline-block, if the texts outside the div and inside the div fit in one line it will not break.
I don’t see the issue of using a here. A line break is a line break, why pretend it’s anything else?
Because there should be a difference in how a document describes a line-break within a block of content from a line-break that is stylistic. In a word: Semantics, son!
In fact this helps with responsive text. brakes always. This way you can just use media queries to let it brake whenever you want. Sorry bout my english. Not native speaker.
How about flexbox?
oooo nice one! It’s weird to think about it cause you don’t often think of text nodes as becoming flex items, but hey, I bet it’s working to spec.
The beauty of the span being a flex-item is that you could use more properties such as
…to position the span on the right, not saying you would in this case but… flexbox is ideal ;) Only downside I can think of is that if for some reason you couldn’t make all of the siblings flex-items.
Morgan, with
display:table
(ordisplay:block; width: fit-content
, as suggested by Šime Vidas below) you can do it, too, withmargin-left: auto
.I use flexbox so much , I almost forgot this was a common issue…
SelenIT, ahaaaa… intrinsic sizing, well… so far that looks like the simplest method. Learnt something there!
my coworker asked me about adding a line break to an h1 header yesterday. this was exactly what went thru my head.
Why not
white-space: nowrap;
on the span so it automatically breaks for you.No need for media queries
nowrap just prevent the content inside the span from breaking.
If the entire H1 fits in one line it will not break.
It would work if we add a huge
margin-right
to it and hide the overflow of the container caused by this margin: http://codepen.io/SelenIT/pen/rLBxodVery limited, but still viable in some situations. But still my personal favourite is
display:table
trick.With a huge margin on the right for the -Element we will have a problem if the text is longer than the box. The text will overflow than because of the overflow: hidden; and could not be read by the user.
I like the table-solution as well.
Berit, completely agree, that’s the limitation of this method.
But
display: table
will make the subsequent text going to the next line instead of being inline with the span element. It’s a trick to make an element like a block, but spanning to the content width instead of the container’s width.You can make the
<div>
inline-block-like withwidth: fit-content
(which isn’t supported in Edge, however). Demo: https://jsbin.com/bexukec/edit?html,css,outputOne more variant:
Why not
white-space: pre-line
?Like this: http://codepen.io/grantbunyan/pen/pbzGMQ/
Of course, you need to to ensure you don’t include a line-break after the opening tag of the parent, but it feels like a very natural solution.
It’s arguably stylistic but only in code formatting, but definitely feels better than adding or removing markup.
All that said, I’ve still no real objection to using
<br>
s in these situations.Out of curiosity, do screen readers speak out the presence of
<br>
s?Maybe it’s just me, but I’d add a
:before
to the<h1>
like so:But maybe I’m missing something…
Thanks for the shout-out, Chris! Definitely agree on the accessibility aspect of using the data-attr trick. I think the
<br>
approach is probably the quickest fix here, but it’s cool to see all these alternatives!h1.two span::before {
content: “\A”;
white-space: pre;
font-family: monospace;
margin: -2em;
color: transparent;
}
→ Seems like left padding in the span is missing then
To avoid missing the left padding:
h1.three span::before {
content: “\A”;
white-space: pre;
font-family: monospace;
margin: -2em;
color: transparent;
-webkit-box-decoration-break: clone;
box-decoration-break: clone;
}
Nice examples. But I’d like to see some more methods for controlling line breaks in responsive design. Anyone in desktop publishing or print design knows how important a line break is: it can visually balance multiple lines, improve readability, and even influence comprehension. But enter responsive design: you now need to consider screen width and how that line break can work across all device sizes.
This is some extracted code from a larger project: http://codepen.io/team/adpearance/pen/QEwEwQ/
The resulting classes give me some control over when breaks should be shown or when the line should just flow naturally. It’s not ideal; I still want some more control on chunking together essential words, but eh…it’s a start.
I’d say many people suggest their variants that just replicate the needed image, not the needed behaviour.
A simple check of adding
text-align: center
on anh1
is needed to prune falsy line-breakers. As in reality, the inline-block span should be centered as a result too, and not stick to the left.Here, I’ve added it to numbers 7 and Thierry’s number 8, which failed.