TIL: Stop Flexbox Removing Trailing Whitespace

The Problem

Today I bumped into a flexbox problem I hadn't seen before. My code looks like this:

For extra assistance, please contact support
<div>
  <span>For extra assistance, please </span>
  <a href="#">contact support</a>
  <div></div>
</div>

Notice the space just before the closing span tag. The idea was that it would look like a normal sentence, but clicking the link would take the user to customer support.

For various reasons, the two texts weren't quite lining up with each other. I thought I could quickly solve the problem with a quick display: flex. But when I did that, something weird happened.

For extra assistance, please contact support
<div className="flex">
  <span>For extra assistance, please </span>
  <a href="#">contact support</a>
  <div></div>
</div>

The trailing space at the end of the span block had disappeared. Why?

The Explanation

For the answer, let's look at the 'white-space' processing model, which describes how the browser handles white space. The part that interests us is how white space at the end of lines is handled:

As each line is laid out, [...] If a space (U+0020) at the end of a line has 'white-space' set to 'normal', 'nowrap', or 'pre-line', it is also removed.

If a space is at the end of a line, it is also removed. Why does this matter?

When we don't use display: flex, the container div has the property display: block. If we don't define the children to be otherwise, the text children are treated as inline elements:

Any text that is directly contained inside a block container element (not inside an inline element) must be treated as an anonymous inline element. - w3.org

Text children of block elements are treated as an anonymous inline element

However, once we use display: flex, we blockify the children:

The display value of a flex item is blockified: if the specified display of an in-flow child of an element generating a flex container is an inline-level value, it computes to its block-level equivalent. - w3.org

In other words, they are treated as if they were display: block. This means the white space is now treated as if it were at the end of a line and is removed.

Text children of flex elements are blockified

The Solution

The 'white-space' processing model also gives us the key to fixing the problem. The rule quoted above only applies when a line has 'white-space' set to 'normal', 'nowrap', or 'pre-line'. We can solve our problem by setting white-space: pre-wrap.

For extra assistance, please contact support
<div className="flex whitespace-pre-wrap">
  <span>For extra assistance, please </span>
  <a href="#">contact support</a>
  <div></div>
</div>

As MDN explains, by using pre-wrap, "sequences of white space are preserved". We could also use white-space: pre, which behaves the same as pre-wrap but prevents text wrapping.