Using JavaScript to Avoid Orphans

Hero image for Using JavaScript to Avoid Orphans. Image by Alice Donovan Rouse.
Hero image for 'Using JavaScript to Avoid Orphans.' Image by Alice Donovan Rouse.

In typography, orphans are often confused with widows (which I tackle in another article here), and occasionally also referred to as 'runts'. However you choose to refer to them, these are those annoying singleword lines that hang alone at the end of a block of text or paragraph:

An excerpt from the letter written by Doc to Marty in Back to the Future II explaining the fate of the DeLorean after he (and it) travelled back to 1885. This type set demonstrates an orphan (or 'runt') word in the final line - highlighted in red.

I say these are annoying, but really any frontend developer who has spent a lot of time with hyperfocused designers knows that the real annoyance comes from watching them laboriously pull their browser window in and out, waiting for that one word to drop onto the next line...

The truth is that whilst in typography and print settings these are a genuine concern that is easily resolved by shortening the previous line, in web development it is extremely difficult to naturally balance text across a fluid screen width and multiple breakpoints without an errant orphan popping up at some point. On some screen width. Somewhere.

There is no simple CSSbased solution and in the past, I have seen it spiral into a significant distraction away from more key components within the project, and all for very little return for the enduser. So: to start with, please do consider whether you really do need to tackle this at all. I would argue that the solution to this type of problem is often a compromise somewhere between design, and content; perhaps with a little input from development.

With all that said, there are some occasions where it does make sense to tackle these and pages can look significantly more accomplished with orphans tendedto. For example in the titles of gridbased listing pages such as Blogs or Product Listings:

Screenshot from a Selfridges.com Product Listing Page demonstrating word wrapping to avoid orphaned words in the product titles.

If you are already resigned to using JavaScript for your front end (which you inevitably are if you are using React), and especially if you're also using serverside rendering, then there is a relatively straightforward solution by using JavaScript to wrap the final two words in a nonbreaking element link a <nobr>.

I've written a little utility function which I can drop in wherever the need arises. You can see it in action in my blog article page titles (above), and on the blog listing pages to help improve the way the text falls on the page:

// import the html parserimport ReactHtmlParser from 'react-html-parser';export default (string) => {  // a little safeguarding: simply return if the  // data passed isn't suitable  if (!string || string.length < 0) {    return string;  }  // trim whitespace and then split into an array  // of words  const words = string.trim().split(' ');  // count the number of words  const totalWords = words.length;  // if there are fewer than four words then don't do anything -  // otherwise we will end up with an orphan on the first  // line instead (!)  if (totalWords < 4) {    return string;  }  // wrap the last two words in a nobr  const formattedLastWords = `<nobr>${words[totalWords - 2]} ${    words[totalWords - 1]  }</nobr>`;  // remove the last two words from the array  words.splice(-2, 2);  // return the remaining words, re-joined with a space, followed  // by the last two words (wrapped in a nobr), as a JSX object  return ReactHtmlParser(`${words.join(' ')} ${formattedLastWords}`);};

All this does is take the last two words of a string and wrap them in a nobr tag, and return the string back with the wrapped final two words as a JSX object. This way the last word will never fall alone: the browser will know to pull the proceeding word down onto the next line to accompany it.

It is important to note here that nobr (the 'nonbreaking text element') was never a standard HTML feature and although in my experience is widely supported across different browsers, may not behave entirely as expected for every user.

The worst that could happen is that it would simply gracefully degrade to (potentially) display an orphan again, but there are also other alternatives you could explore such as using the CSS whitespace property on a span instead. Although using an inline style attribute this has a very slight clientside performance impact of its own:

const formattedLastWords = `<span style="white-space: nowrap;">    ${words[totalWords - 2]} ${words[totalWords - 1]}  </span>`;

Whether you chose to use nobr or whitespace, both achieve the same effect and this approach works well. In practice though, there will always be edge cases where twoword wrapping is less elegant onscreen, and in these situations, we fall back to the designerdevelopercontent compromise. As a brief example, where I use this for article titles on my blog page, I found that there were occasions where the length of the final word meant that pulling it down onto the next line along with its preceding compatriot, left the text looking misbalanced:

Screenshot of three different grid items on the johnkavanagh.co.uk blog demonstrating wrapping the last two words to avoid an orphan.

In my case, this was easily resolved by adjusting my utility function to first measure the number of letters in the final word, before deciding whether to inject a nonbreaking span or not. However, this does also add more unnecessary complexity to something that you could probably argue is superfluous in modern, responsive, websites anyway.


Categories:

  1. Development
  2. Front‑End Development
  3. JavaScript
  4. Typography