Skip to content

4 August 2026 · 7 min read

Arabic type is not Latin type in another alphabet

Why the same font size, line height and grid produce a worse page in Arabic, and the handful of CSS rules that fix it.

A bilingual site usually gets built once, in English, and then has Arabic poured into the same containers. The result is legible. It is rarely good, and the reasons are structural rather than aesthetic — Arabic script has different metrics, and a layout tuned for one will be wrong for the other in predictable ways.

There are no capitals, so there are no anchors

Latin readers navigate a page partly by capital letters. They mark the start of a sentence, a proper noun, a heading. Arabic has no case distinction at all.

Two consequences follow. First, techniques that lean on capitals stop working: text-transform: uppercase does nothing to Arabic, and small-caps has no meaning. An eyebrow label styled as uppercase-with-wide-tracking simply renders as normal Arabic text at a small size, which reads as an afterthought rather than a deliberate label.

Second, and more importantly, hierarchy has to come from somewhere else — weight, size, colour and space, rather than case. A design that separated a label from body text only by capitalisation has no hierarchy at all once translated.

Arabic needs more line height, not the same

Arabic letterforms carry marks above and below the baseline, and the script has a taller effective ascender-descender range than Latin at the same nominal size. Set both at line-height: 1.5 and the Arabic looks cramped — diacritics come close to colliding with the line above.

A reasonable starting point is a noticeably looser leading for Arabic than for the same Latin size. The mechanism matters more than the exact number: apply it by language, not by a wrapper class someone has to remember.

:lang(ar) {
  line-height: 1.85;
}

:lang(ar) h1,
:lang(ar) h2 {
  line-height: 1.4;
}

:lang() matches on the document’s declared language, so it follows <html lang="ar"> without any component needing to know which locale it is in. That detail is what keeps it from rotting: a new component inherits correct Arabic leading for free, and nobody has to remember a modifier.

One caveat if you use a utility framework: those utilities are usually generated into a cascade layer, and an unlayered rule beats a layered one regardless of specificity. If your :lang() rules sit outside the layer, they will win over leading-* utilities — which is what you want here, but it is worth knowing rather than discovering.

Font size is not comparable across scripts

The same font-size produces visually smaller Arabic than Latin, because the x-height equivalent sits differently relative to the em box. Arabic set at the same nominal size as its English counterpart looks a step down in the hierarchy even when it is the same heading.

You cannot fix this by picking a bigger number everywhere — that breaks the vertical rhythm. Set it per language, in the same place you set the leading, and verify by looking at the two side by side rather than by comparing the numbers.

Not every font has an Arabic counterpart

This is the constraint that most often derails a brand system. A brand picks a Latin display face, and there is no matching Arabic face — not merely no official one, but nothing with the same voice, weight range or proportions.

There are three honest options and one dishonest one.

The dishonest one is letting the browser substitute. If your font-family lists only a Latin face, Arabic falls through to whatever the operating system provides, which means your Arabic pages are typeset in a different font on Windows, macOS, Android and iOS. You have not chosen a typeface; you have declined to.

The honest options: pair the Latin face with an Arabic family designed as a companion; use a superfamily that ships both scripts; or accept a deliberate mismatch you have actually looked at and approved. All three are defensible. Substitution by accident is not.

Whatever you choose, declare it explicitly and per-language, so no page is ever typeset by a fallback nobody selected.

Numbers stay left-to-right, always

Digits, prices, phone numbers, product codes and dates run left-to-right inside Arabic text. The bidirectional algorithm handles most of this, but it fails around punctuation — a phone number with + and spaces, or a range like 2020–2024, can reorder in ways that change meaning.

Mark the run explicitly, on the smallest inline element that contains it:

<span dir="ltr">+963 99 20 444 50</span>

Do not put that dir on the containing block. dir sets alignment as well as bidi context, so a block-level dir="ltr" inside an Arabic page will left-align its contents while everything around it stays right-aligned. It looks like a broken grid and the cause is one attribute one level too high.

Also decide whether you are using Western digits (0-9) or Eastern Arabic numerals (٠-٩). Both are correct; mixing them within one interface is not. Most contemporary web products in the region use Western digits, and consistency matters more than the choice.

Justification behaves differently

Arabic traditionally justifies by extending the connecting strokes between letters — kashida — rather than by stretching word spaces. Browsers do not do this well. text-align: justify on Arabic produces uneven word gaps that are more distracting than a ragged edge.

Leave it aligned to start. Ragged is fine; rivers of white space are not.

What to check before shipping

  • Render every page in both languages at the same viewport and compare heading sizes optically, not numerically.
  • Confirm no Arabic text falls back to a system font. Check computed font-family on an Arabic paragraph in a browser, not in the stylesheet.
  • Confirm text-transform: uppercase is not carrying hierarchy anywhere.
  • Check every number, price and date renders in the order it was written.
  • Read one long paragraph in Arabic at body size. If your eye loses the line, the leading is too tight.

The underlying point

None of this is about translation quality. A perfectly translated page set in a substituted font, at Latin leading, with uppercase labels that do nothing, will still read as a second-class version of the English.

Treating Arabic as a first-class typographic system — its own leading, its own size, its own declared typeface — costs a handful of CSS rules if you do it at the start. It costs a redesign if you do it later.

Get in touch

Tell us what is stuck

Thirty minutes, no slides needed. Tell us the problem and we will come back with our first read on it.

What happens next

  1. 1. You pick a time, or just send us the problem.
  2. 2. We reply within one working day.
  3. 3. You get our first read on it. No charge, no deck.