Hyphenate headings as a last resort
Before I forgot about blogging for nine years in 2012, my last post here was about hyphenation. Surely things progressed since then, right?
Right?
(Not really.)
Need for hyphenation
Most of the time there is no need for hyphenation and text looks fine
aligned to the left start1. Where hyphenation comes in
really handy is headings. It’s easy to end up with a heading set in
a relatively large size and somebody will at some point put a
very–long–word™ there. Then browsers with narrow viewport will start
adding horizontal scrolling or – gasp! – your whole page will
be shrunk to accommodate the offending word.
Ok. Let’s start putting some long words in narrow containers and see what happens.
By default words are not hyphenated and just stick out of the container.
hyphens: auto
One would hope that adding hyphens: auto
would
make things just work, but there are a few problems with it:
-
Uncharacteristically
is not hyphenated. What gives?Turns out currently both Chrome and Firefox disable hyphenation of capitalised words2. This is to avoid performing it on proper nouns. Good intention, but it significantly limits usage of hyphenation in headings, which usually starts with a capitalised word or even have all of them capitalised.
-
extraordinarily
is short enough to fit in a line, but gets hyphenated.Browsers are eager to hyphenate. In our case we want to hyphenate words only as a last resort, when whole word doesn’t fit in a line – that’s currently not possible with CSS.
We could use
hyphenate-limit-chars
to make the situation better to some extend, but it’s not perfect and it’s only supported by Chrome. -
Not visible in this example, but browser needs to support hyphenation for your language. Check out
hyphens
browser compatibility table on MDN – support for non–English is spotty to seat the least (👏 for Firefox).
Soft hyphens
You can instruct browsers of places where words can be broken using
­
HTML entity (or U-00AD
Soft Hyphen character). This takes care
of capitalised words. As a bonus it also brings hyphenation to browsers
that don’t support hyphens: auto
(at all or in your language).
Alas, hyphenation is still performed too eagerly. While we like that
Uncharacteristically
is broken into two lines, since it’s longer
than our container, extraordinarily
is not and could be carried
over to a next line.
The solution
Let’s try to address the shortcomings of previous attempts with what we have at our disposal in 2023.
You will not like it.
In addition to adding soft hyphens, wrap each word in an element with
display: inline-block
.
This will prefer carrying whole block to the next line before hyphenating. Effectively only breaking the word as a last resort – when it doesn’t fit in the line on it’s own.
Here’s a JavaScript snippet to process your headings (you are a responsible adult and will do it only on server side, right?):
import { hyphenateSync } from 'hyphens/en';
hyphenateSync(text.trim())
.split(/\s+/)
.map(word => `<span class=word>${word}</span>`)
.join(' ');
Note that this will increase weight of your HTML, so probably don’t run it everywhere. I’d only do it on headings and other elements that will be displayed in a bigger font.
This solution definitely has a distinct ’90s smell all over it and makes you feel dirty when implementing it, but it does work.
The future
There is a discussion on CSS WG about allowing hyphenating capitalised
words. With this and
hyphenate-limit-chars
we’ll hopefully get
a reasonable CSS–only solution in the future.