there’s no place like code

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.

Uncharacteristically and also extraordinarily long English words.

hyphens: auto

One would hope that adding hyphens: auto would make things just work, but there are a few problems with it:

  1. 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.

  2. 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.

  3. 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.