Skip to article body
A man in an old Cairo workshop pulling one long thread through plain periwinkle cloth, his arm smeared by motion
A man in an old Cairo workshop pulling one long thread through plain periwinkle cloth, his arm smeared by motion

Web Development · Typography

You Can't Split an Arabic Word

What per letter text animation does to Arabic, and to the Latin text living beside it.

By Shehab Waleed, Founder, Cairo Studio 3 min read

Most text reveals on the web start the same way: split the line into words or letters, wrap each in an inline-block span, and stagger them. We use that pattern across our site. When we built the Arabic version, it broke in two separate ways, and only one of them involved Arabic.

Arabic letters depend on their neighbours

Most Arabic letters have different forms for the start, middle and end of a word, and the browser picks one by looking at what sits next to it. Wrap each letter in its own inline-block and the browser shapes it alone.

Whole: مدينة

Split: م د ي ن ة

You can measure the damage. In Chromium at 40px, that word is 70.5px wide when whole and 93.6px wide when split by letter, because each letter falls back to its wider isolated form. Splitting by word keeps the joins, since Arabic only joins inside a word.

Letter spacing breaks the joins as well, and tracking tends to live in shared classes where nobody thinks about Arabic. We reset it at the top.

[lang='ar'] [class*='tracking-'] {
letter-spacing: normal;
}

So we stopped splitting it

Our text components ask the same question first.

const ARABIC =
/[\u0600-\u06FF\u0750-\u077F\u08A0-\u08FF\uFB50-\uFDFF\uFE70-\uFEFF]/;

export function hasArabic(value) {
return !!value && ARABIC.test(value);
}

If the answer is yes, the whole line animates as one unit. Word splitting would survive, but one check and no splitting is a simpler rule, and it removes any question about word order.

let targets;
if (hasArabic(value)) {
targets = [inner];
} else {
split = new SplitText(inner, { type: 'words' });
targets = split.words;
}

The bug that hit the English

Arabic pages still carry Latin text: service codes like BR and UX, numbers, project names. Under dir="rtl" these came out wrong. An inline-block counts as a neutral object in the bidi algorithm, so a row of them gets laid out from right to left, even when each one holds a Latin letter. Text that was never split gets reordered too, because nothing isolates it from the page direction. These are from our audit in headless Chrome.

  • BR became RB.
  • UX became XU.
  • 32 Real Estate became Real Estate 32.
  • [S: 01] became 01] [S:

The fix for a splitter is one attribute on the element being split. In a bare test, the same two spans read RB without it and BR with it.

<span dir={hasArabic(text) ? 'rtl' : 'ltr'}>{text}</span>

When a component needs left to right geometry, like a horizontal track, set dir="ltr" on the track and restore the direction on each text panel inside it. Putting dir="ltr" on a whole section leaks into its headings and into every logical utility inside.

<div dir="ltr" class="track">
<div dir={isRtl ? 'rtl' : 'ltr'}>...</div>
</div>

Arabic type needs more room

Thmanyah, our Arabic display face, measures 1.434em from top to bottom of its ink. Youth, our Latin header face, measures 1.243em. A line height of 0.85 that looks sharp in English will clip Arabic, which needs at least 1.35 for display and 1.7 for body text.

Font order matters too. Thmanyah also covers Latin, from a serif half, so it has to come after the Latin face or your codes and numbers turn into serifs.

--font-header: 'Youth', 'Thmanyah Display', sans-serif;

None of this replaces writing the Arabic properly in the first place. It only makes sure the browser does not undo that work.

Share
X LinkedIn Facebook WhatsApp Email
Hands pulling a single thread through dark cloth, the thread smeared into one continuous curve

One thread, start to end.

Latin
Words or letters
Arabic
The whole line
Latin
Tight tracking is fine
Arabic
Normal, always
Latin
0.85 to 1.05
Arabic
1.35 or more
Latin
Whatever suits the face
Arabic
1.7 or more
Latin
dir="ltr" on the split element
Arabic
dir="rtl" on the split element

Values from our own site, with Youth and Thmanyah Display.

Never by character, since each letter loses its joins. Splitting by word keeps the letters joined. We chose to animate whole lines instead, because it is one simple rule across every component.

Text split into inline-block spans is laid out by the page direction, so an RTL page runs the letters from right to left. Add dir="ltr" to the element you split.

It pulls the joined letters apart, so it breaks the connections between them. Reset it to normal on any Arabic text.

We design and build bilingual sites where both languages get the same care, down to how the type moves.

See our web development work

More from the Journal

view all →