A comprehensive guide to selecting, pairing, and optimizing Arabic web fonts for performance and readability.

Amira Hassan
Linguist and typographer specializing in Arabic script history and evolution.
Typography is the foundation of good design, and in Arabic web development, choosing the right font is more critical than many realize. Arabic script has unique characteristics that make font selection both challenging and crucial: connected letters, contextual forms, optional diacritics, and varied calligraphic traditions.
Unlike Latin fonts where any readable typeface will generally work, Arabic fonts can dramatically affect readability, cultural appropriateness, and technical performance. A poor font choice can make your content difficult to read or culturally mismatched to your audience.
The good news? The Arabic web font landscape has matured significantly in recent years. We now have excellent options that balance tradition with modern design sensibilities.
Arabic fonts are typically 2-3x larger than equivalent Latin fonts due to the complexity of letter forms, contextual shaping, and ligature requirements. Performance optimization is essential.
Before diving into specific fonts, let's understand the two major style categories:
Naskh (نسخ) is the standard style used for body text. It's what you see in most books, newspapers, and websites. Naskh is characterized by:
Best for: Body text, articles, documentation, formal content
Kufi (كوفي) is more geometric and angular. Modern Kufi fonts are often used for:
Best for: Headings, UI elements, logos, display text
Let's examine the most popular and reliable Arabic web fonts available today.
Type: Sans-serif, Kufi-inspired Designer: Google Fonts Weights: 9 weights (Thin to Black)
Characteristics:
File size: ~150KB (Regular weight, woff2)
Best use cases:
@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+Arabic:wght@100..900&display=swap');
body {
font-family: 'Noto Sans Arabic', sans-serif;
}Noto Sans Arabic is an excellent default choice for web applications. Its wide character support and multiple weights make it versatile and reliable.
Type: Sans-serif, geometric Designer: Mohamed Gaber Weights: 7 weights (ExtraLight to Black)
Characteristics:
File size: ~120KB (Regular weight, woff2)
Best use cases:
@import url('https://fonts.googleapis.com/css2?family=Cairo:wght@200..1000&display=swap');
.heading {
font-family: 'Cairo', sans-serif;
font-weight: 700;
}Type: Sans-serif Designer: IBM (Bold Monday studio) Weights: 7 weights (Thin to Bold)
Characteristics:
File size: ~135KB (Regular weight, woff2)
Best use cases:
@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Sans+Arabic:wght@100..700&display=swap');
.corporate-text {
font-family: 'IBM Plex Sans Arabic', sans-serif;
}

Type: Sans-serif, Kufi-style Designer: Boutros International Weights: 5 weights (ExtraLight to Black)
Characteristics:
File size: ~85KB (Regular weight, woff2)
Best use cases:
@import url('https://fonts.googleapis.com/css2?family=Tajawal:wght@200..900&display=swap');
.button {
font-family: 'Tajawal', sans-serif;
font-weight: 500;
}Type: Serif, Naskh style Designer: Khaled Hosny Weights: 2 weights (Regular, Bold)
Characteristics:
File size: ~185KB (Regular weight, woff2)
Best use cases:
@import url('https://fonts.googleapis.com/css2?family=Amiri:wght@400;700&display=swap');
.traditional-text {
font-family: 'Amiri', serif;
line-height: 1.8; /* Naskh needs more line-height */
}Amiri includes extensive support for Quranic text, including all diacritical marks and special symbols. If you're displaying religious content, this is your best choice.
Type: Variable font, Sans-serif Designer: Thomas Jockin (for Google Fonts) Weights: Variable (200-700)
Characteristics:
File size: ~145KB (variable font, woff2)
Best use cases:
@import url('https://fonts.googleapis.com/css2?family=Readex+Pro:wght@200..700&display=swap');
.reading-interface {
font-family: 'Readex Pro', sans-serif;
font-variation-settings: 'wght' 350; /* Variable font control */
}| Font | Style | Weights | File Size | Best For | Performance |
|---|---|---|---|---|---|
| Noto Sans Arabic | Sans-serif (Kufi) | 9 | ~150KB | General purpose, apps | Good |
| Cairo | Sans-serif (Geometric) | 7 | ~120KB | Modern websites | Excellent |
| IBM Plex Arabic | Sans-serif | 7 | ~135KB | Enterprise, corporate | Good |
| Tajawal | Sans-serif (Kufi) | 5 | ~85KB | UI, mobile | Excellent |
| Amiri | Serif (Naskh) | 2 | ~185KB | Traditional, formal | Moderate |
| Readex Pro | Variable | Variable | ~145KB | Reading apps | Good |
Most bilingual websites need both Arabic and Latin scripts. Here's how to pair them effectively:
/* Pairing 1: Noto Sans Arabic + Noto Sans */
:root {
--font-ar: 'Noto Sans Arabic', sans-serif;
--font-en: 'Noto Sans', sans-serif;
}
/* Pairing 2: Cairo + Inter */
:root {
--font-ar: 'Cairo', sans-serif;
--font-en: 'Inter', sans-serif;
}
/* Pairing 3: IBM Plex Sans Arabic + IBM Plex Sans */
:root {
--font-ar: 'IBM Plex Sans Arabic', sans-serif;
--font-en: 'IBM Plex Sans', sans-serif;
}
/* Pairing 4: Tajawal + Roboto */
:root {
--font-ar: 'Tajawal', sans-serif;
--font-en: 'Roboto', sans-serif;
}
/* Pairing 5: Amiri + Crimson Pro */
:root {
--font-ar: 'Amiri', serif;
--font-en: 'Crimson Pro', serif;
}
/* Usage with language detection */
body {
font-family: var(--font-en);
}
:lang(ar) {
font-family: var(--font-ar);
}The Noto font family (Noto Sans Arabic + Noto Sans) is specifically designed to work together across all scripts. If you want guaranteed harmony, start there.
When testing font pairings, check these scenarios:
<!-- Mixed content test -->
<p lang="ar">
مرحباً بك في <span lang="en">GitHub</span> العربي
</p>
<!-- UI element test -->
<button>
<span lang="ar">إضافة</span> Product
</button>
<!-- Navigation test -->
<nav>
<a href="/" lang="ar">الرئيسية</a>
<a href="/products">Products</a>
</nav>Look for jarring size differences, weight mismatches, or awkward spacing.
Arabic fonts are large. Here's how to load them efficiently:
Only load the characters you need:
<!-- Google Fonts: Specify text parameter -->
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+Arabic:wght@400;700&text=أبتثجحخدذرزسشصضطظعغفقكلمنهويءآإؤئ" rel="stylesheet">Or use font subsetting tools:
# Using glyphhanger
npm install -g glyphhanger
# Subset a font file
glyphhanger --subset=font.ttf --formats=woff2 --cssControl how fonts load and prevent layout shifts:
@font-face {
font-family: 'Noto Sans Arabic';
src: url('/fonts/noto-sans-arabic.woff2') format('woff2');
font-display: swap; /* Show fallback, swap when loaded */
font-weight: 400;
font-style: normal;
}font-display options:
swap - Show fallback immediately, swap when loaded (recommended)block - Brief invisible period, then show fontfallback - Very brief invisible period, swap if loaded quickly, otherwise stay with fallbackoptional - Let browser decide based on connection speedAvoid font-display: block for Arabic fonts. The file sizes can cause long blocking periods, creating a poor user experience. Use swap instead.
For fonts used above the fold:
<link rel="preload" href="/fonts/noto-sans-arabic-regular.woff2" as="font" type="font/woff2" crossorigin>If you need many weights, consider variable fonts:
@font-face {
font-family: 'Readex Pro';
src: url('/fonts/readex-pro-variable.woff2') format('woff2-variations');
font-weight: 200 700; /* Full range in one file */
font-display: swap;
}
/* Use any weight */
.heading {
font-weight: 350; /* Exact weight */
}Self-hosting gives you more control:
/* fonts.css */
@font-face {
font-family: 'Cairo';
src: url('/fonts/cairo-regular.woff2') format('woff2');
font-weight: 400;
font-display: swap;
/* Unicode range for Arabic */
unicode-range: U+0600-06FF, U+FB50-FDFF, U+FE70-FEFF;
}
@font-face {
font-family: 'Cairo';
src: url('/fonts/cairo-bold.woff2') format('woff2');
font-weight: 700;
font-display: swap;
unicode-range: U+0600-06FF, U+FB50-FDFF, U+FE70-FEFF;
}

Arabic text needs different spacing than Latin:
/* Latin text */
.text-latin {
font-size: 16px;
line-height: 1.5; /* 24px */
letter-spacing: 0;
}
/* Arabic text */
.text-arabic {
font-size: 16px;
line-height: 1.8; /* 28.8px - More space for diacritics */
letter-spacing: 0; /* Never add letter-spacing to Arabic! */
}Never use letter-spacing on Arabic text. It breaks the connections between letters and destroys the script's visual integrity.
Naskh fonts (like Amiri) need more line-height:
.naskh-text {
font-family: 'Amiri', serif;
line-height: 2.0; /* Generous spacing */
}Kufi fonts (like Cairo, Tajawal) are more compact:
.kufi-text {
font-family: 'Cairo', sans-serif;
line-height: 1.6; /* Less spacing needed */
}Here's a quick decision tree:
Need a safe, versatile default? → Noto Sans Arabic
Building a modern startup or tech product? → Cairo
Creating an enterprise dashboard? → IBM Plex Sans Arabic
Optimizing for mobile or performance? → Tajawal
Displaying traditional, literary, or religious content? → Amiri
Building a reading interface? → Readex Pro
Need multiple weights efficiently? → Readex Pro (variable font)
A comprehensive guide to selecting, pairing, and optimizing Arabic web fonts for performance and readability.

Amira Hassan
Linguist and typographer specializing in Arabic script history and evolution.
Typography is the foundation of good design, and in Arabic web development, choosing the right font is more critical than many realize. Arabic script has unique characteristics that make font selection both challenging and crucial: connected letters, contextual forms, optional diacritics, and varied calligraphic traditions.
Unlike Latin fonts where any readable typeface will generally work, Arabic fonts can dramatically affect readability, cultural appropriateness, and technical performance. A poor font choice can make your content difficult to read or culturally mismatched to your audience.
The good news? The Arabic web font landscape has matured significantly in recent years. We now have excellent options that balance tradition with modern design sensibilities.
Arabic fonts are typically 2-3x larger than equivalent Latin fonts due to the complexity of letter forms, contextual shaping, and ligature requirements. Performance optimization is essential.
Before diving into specific fonts, let's understand the two major style categories:
Naskh (نسخ) is the standard style used for body text. It's what you see in most books, newspapers, and websites. Naskh is characterized by:
Best for: Body text, articles, documentation, formal content
Kufi (كوفي) is more geometric and angular. Modern Kufi fonts are often used for:
Best for: Headings, UI elements, logos, display text
Let's examine the most popular and reliable Arabic web fonts available today.
Type: Sans-serif, Kufi-inspired Designer: Google Fonts Weights: 9 weights (Thin to Black)
Characteristics:
File size: ~150KB (Regular weight, woff2)
Best use cases:
@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+Arabic:wght@100..900&display=swap');
body {
font-family: 'Noto Sans Arabic', sans-serif;
}Noto Sans Arabic is an excellent default choice for web applications. Its wide character support and multiple weights make it versatile and reliable.
Type: Sans-serif, geometric Designer: Mohamed Gaber Weights: 7 weights (ExtraLight to Black)
Characteristics:
File size: ~120KB (Regular weight, woff2)
Best use cases:
@import url('https://fonts.googleapis.com/css2?family=Cairo:wght@200..1000&display=swap');
.heading {
font-family: 'Cairo', sans-serif;
font-weight: 700;
}Type: Sans-serif Designer: IBM (Bold Monday studio) Weights: 7 weights (Thin to Bold)
Characteristics:
File size: ~135KB (Regular weight, woff2)
Best use cases:
@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Sans+Arabic:wght@100..700&display=swap');
.corporate-text {
font-family: 'IBM Plex Sans Arabic', sans-serif;
}

Type: Sans-serif, Kufi-style Designer: Boutros International Weights: 5 weights (ExtraLight to Black)
Characteristics:
File size: ~85KB (Regular weight, woff2)
Best use cases:
@import url('https://fonts.googleapis.com/css2?family=Tajawal:wght@200..900&display=swap');
.button {
font-family: 'Tajawal', sans-serif;
font-weight: 500;
}Type: Serif, Naskh style Designer: Khaled Hosny Weights: 2 weights (Regular, Bold)
Characteristics:
File size: ~185KB (Regular weight, woff2)
Best use cases:
@import url('https://fonts.googleapis.com/css2?family=Amiri:wght@400;700&display=swap');
.traditional-text {
font-family: 'Amiri', serif;
line-height: 1.8; /* Naskh needs more line-height */
}Amiri includes extensive support for Quranic text, including all diacritical marks and special symbols. If you're displaying religious content, this is your best choice.
Type: Variable font, Sans-serif Designer: Thomas Jockin (for Google Fonts) Weights: Variable (200-700)
Characteristics:
File size: ~145KB (variable font, woff2)
Best use cases:
@import url('https://fonts.googleapis.com/css2?family=Readex+Pro:wght@200..700&display=swap');
.reading-interface {
font-family: 'Readex Pro', sans-serif;
font-variation-settings: 'wght' 350; /* Variable font control */
}| Font | Style | Weights | File Size | Best For | Performance |
|---|---|---|---|---|---|
| Noto Sans Arabic | Sans-serif (Kufi) | 9 | ~150KB | General purpose, apps | Good |
| Cairo | Sans-serif (Geometric) | 7 | ~120KB | Modern websites | Excellent |
| IBM Plex Arabic | Sans-serif | 7 | ~135KB | Enterprise, corporate | Good |
| Tajawal | Sans-serif (Kufi) | 5 | ~85KB | UI, mobile | Excellent |
| Amiri | Serif (Naskh) | 2 | ~185KB | Traditional, formal | Moderate |
| Readex Pro | Variable | Variable | ~145KB | Reading apps | Good |
Most bilingual websites need both Arabic and Latin scripts. Here's how to pair them effectively:
/* Pairing 1: Noto Sans Arabic + Noto Sans */
:root {
--font-ar: 'Noto Sans Arabic', sans-serif;
--font-en: 'Noto Sans', sans-serif;
}
/* Pairing 2: Cairo + Inter */
:root {
--font-ar: 'Cairo', sans-serif;
--font-en: 'Inter', sans-serif;
}
/* Pairing 3: IBM Plex Sans Arabic + IBM Plex Sans */
:root {
--font-ar: 'IBM Plex Sans Arabic', sans-serif;
--font-en: 'IBM Plex Sans', sans-serif;
}
/* Pairing 4: Tajawal + Roboto */
:root {
--font-ar: 'Tajawal', sans-serif;
--font-en: 'Roboto', sans-serif;
}
/* Pairing 5: Amiri + Crimson Pro */
:root {
--font-ar: 'Amiri', serif;
--font-en: 'Crimson Pro', serif;
}
/* Usage with language detection */
body {
font-family: var(--font-en);
}
:lang(ar) {
font-family: var(--font-ar);
}The Noto font family (Noto Sans Arabic + Noto Sans) is specifically designed to work together across all scripts. If you want guaranteed harmony, start there.
When testing font pairings, check these scenarios:
<!-- Mixed content test -->
<p lang="ar">
مرحباً بك في <span lang="en">GitHub</span> العربي
</p>
<!-- UI element test -->
<button>
<span lang="ar">إضافة</span> Product
</button>
<!-- Navigation test -->
<nav>
<a href="/" lang="ar">الرئيسية</a>
<a href="/products">Products</a>
</nav>Look for jarring size differences, weight mismatches, or awkward spacing.
Arabic fonts are large. Here's how to load them efficiently:
Only load the characters you need:
<!-- Google Fonts: Specify text parameter -->
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+Arabic:wght@400;700&text=أبتثجحخدذرزسشصضطظعغفقكلمنهويءآإؤئ" rel="stylesheet">Or use font subsetting tools:
# Using glyphhanger
npm install -g glyphhanger
# Subset a font file
glyphhanger --subset=font.ttf --formats=woff2 --cssControl how fonts load and prevent layout shifts:
@font-face {
font-family: 'Noto Sans Arabic';
src: url('/fonts/noto-sans-arabic.woff2') format('woff2');
font-display: swap; /* Show fallback, swap when loaded */
font-weight: 400;
font-style: normal;
}font-display options:
swap - Show fallback immediately, swap when loaded (recommended)block - Brief invisible period, then show fontfallback - Very brief invisible period, swap if loaded quickly, otherwise stay with fallbackoptional - Let browser decide based on connection speedAvoid font-display: block for Arabic fonts. The file sizes can cause long blocking periods, creating a poor user experience. Use swap instead.
For fonts used above the fold:
<link rel="preload" href="/fonts/noto-sans-arabic-regular.woff2" as="font" type="font/woff2" crossorigin>If you need many weights, consider variable fonts:
@font-face {
font-family: 'Readex Pro';
src: url('/fonts/readex-pro-variable.woff2') format('woff2-variations');
font-weight: 200 700; /* Full range in one file */
font-display: swap;
}
/* Use any weight */
.heading {
font-weight: 350; /* Exact weight */
}Self-hosting gives you more control:
/* fonts.css */
@font-face {
font-family: 'Cairo';
src: url('/fonts/cairo-regular.woff2') format('woff2');
font-weight: 400;
font-display: swap;
/* Unicode range for Arabic */
unicode-range: U+0600-06FF, U+FB50-FDFF, U+FE70-FEFF;
}
@font-face {
font-family: 'Cairo';
src: url('/fonts/cairo-bold.woff2') format('woff2');
font-weight: 700;
font-display: swap;
unicode-range: U+0600-06FF, U+FB50-FDFF, U+FE70-FEFF;
}

Arabic text needs different spacing than Latin:
/* Latin text */
.text-latin {
font-size: 16px;
line-height: 1.5; /* 24px */
letter-spacing: 0;
}
/* Arabic text */
.text-arabic {
font-size: 16px;
line-height: 1.8; /* 28.8px - More space for diacritics */
letter-spacing: 0; /* Never add letter-spacing to Arabic! */
}Never use letter-spacing on Arabic text. It breaks the connections between letters and destroys the script's visual integrity.
Naskh fonts (like Amiri) need more line-height:
.naskh-text {
font-family: 'Amiri', serif;
line-height: 2.0; /* Generous spacing */
}Kufi fonts (like Cairo, Tajawal) are more compact:
.kufi-text {
font-family: 'Cairo', sans-serif;
line-height: 1.6; /* Less spacing needed */
}Here's a quick decision tree:
Need a safe, versatile default? → Noto Sans Arabic
Building a modern startup or tech product? → Cairo
Creating an enterprise dashboard? → IBM Plex Sans Arabic
Optimizing for mobile or performance? → Tajawal
Displaying traditional, literary, or religious content? → Amiri
Building a reading interface? → Readex Pro
Need multiple weights efficiently? → Readex Pro (variable font)