Visually spaced phone and IBAN numbers using HTML and CSS
Tags: css, webdev, ux
Published: 2022-06-29 10:23:43

How to display numbers that should be both human-readable and machine-readable? An international bank account number ([IBAN](https://en.wikipedia.org/wiki/International_Bank_Account_Number)) is a very long numeric code like `DE89430609673029840000` which becomes hard to read for the human eye. The standard recommends to write blocks of four digits, so the number becomes `DE89 4306 0967 3029 8400 00`.

## Human-Readable + Machine-Readable

But this human-readable block-of-four notation causes problems when people copy and paste the formatted bank code into an input fields that uses an HTML form field validation or a similar JavaScript evaluation which often does not accept spaces (which is a usability failure, but still common practice).

![Screenshot of a validation error](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uwk2a2mgagphev096ay5.png)

Writing phone numbers causes a similar challenge. We want to present a correct international machine-readable phone number, linked as a `tel:` url, but which is also easy to read and memorize for our human customers at the same time!

### CSS Adjacent Sibling Selector

Of course there is a solution using CSS, but we have to change our HTML markup as well, using `<span>`s for each visually separated block.

```html
<span class="visually-spaced">DE89</span><span class="visually-spaced">4306</span><span class="visually-spaced">0967</span><span class="visually-spaced">3029</span><span class="visually-spaced">8400</span><span class="visually-spaced">00</span>
```

We can now use `::before` pseudo elements to add a visual space between the elements. Using the [adjacent sibling selector (plus sign "+")](https://www.w3.org/TR/CSS21/selector.html#adjacent-selectors) there will be no space before the first block.

```css
visually-spaced+.visually-spaced:before {
    content: " ";
    letter-spacing: .25rem;
}
```

Now it looks like distinct blocks, but the content contains no white-space characters, so when we copy and paste the line of visually separated blocks, it becomes one single block without any separating characters in between.

![Screenshot of selected bank account number and developer tools showing the markup explained above.](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/27zigved7qb7d7po4p9o.png)

## Continuous Underline

So far, we could have achieved the same effect using `margin` or `padding` without pseudo elements, or set a width on our pseudo elements, but when we want to link our formatted content and underline the link, the underline would be broken between the blocks.

![Screenshot of formatting variations shown in the codepen](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l7h9dpqw7o7f7l9m0jk9.png)

You can see the example above in [this codepen](https://codepen.io/openmindculture/pen/YzazRZo).

## Maintaining Developer Experience (DX)

So we used some CSS and HTML markup to improve our user experience (UX), but what about developer experience (DX)? Now our source code has become less readable so it has become harder to edit and maintain our code.

```html
before:
DE89 4306 0967 3029 8400 00

after:
<span class="visually-spaced">DE89</span><span class="visually-spaced">4306</span><span class="visually-spaced">0967</span><span class="visually-spaced">3029</span><span class="visually-spaced">8400</span><span class="visually-spaced">00</span>
```

But in 2022 we rarely edit our source code manually. Most content will be generated by some content management system (CMS) or site builder (like [11ty](https://www.11ty.dev) or another [Jamstack](https://jamstack.org/) tool).

Using `liquid` code to generate multiple language versions of my content, my before vs. after situation actually looks like this.

### Before: print a localized content string

```js
JSON:
  "bankaccountNumber": "DE89 4306 0967 3029 8400 00"
```

```liquid
Liquid:
{{ content.bankaccountNumber }}
```

### After: iterate over an array of strings

```js
JSON:
  "bankaccountNumberChunks": [
    "DE89",
    "4306",
    "0967",
    "3029",
    "8400",
    "00"
  ],
```

```liquid
Liquid:
{%- for chunk in content.bankaccountNumberChunks -%}<span class="visually-spaced">{{ chunk }}</span>{%- endfor -%}            
```

A practical example of this formatting technique can be found on my own website: [www.ingo-steinke.com/#contact](https://www.ingo-steinke.com/#contact)