5 min read · 2026-10-26

What an Arabic webfont actually weighs

Measured WOFF2 sizes for Arabic families, why the Arabic subset can be lighter than the Latin one, and what to do about it.

Every family on Google Fonts that ships an Arabic subset, measured in one pass: 57 families, the WOFF2 files Google actually serves at weight 400, counted in bytes. At the median the Arabic file is 1.35× the size of the same family's Latin file — and the range around that median runs from 0.50× to 12.75×.

Measured WOFF2, weight 400 requested with 700, kilobytes
family Arabic Latin ratio
Noto Nastaliq Urdu 233 20 11.67×
Gulzar 204 25 8.29×
Noto Sans Arabic 162 31 5.28×
Cairo 30 33 0.91×
Tajawal 9 10 0.87×

Why the spread is that wide

A Naskh face drawn for interface text carries a few hundred glyphs. A Nastaliq face carries thousands, because the script's shaping rules stack and join letters into context-dependent forms that cannot be composed from a base glyph plus marks. Gulzar and Noto Nastaliq Urdu are beautiful for poetry and expensive for a product page. Cairo and Tajawal compile to something smaller than their own Latin companion, which is the opposite of the folk rule.

That is the argument for measuring: the ratio is a property of an individual drawing, not of a script.

Ask for one weight, get a smaller file

The same family weighs very differently depending on the CSS you requested it with. Ask Google for a range of weights and you get the variable file, which carries the whole axis. Ask for a single weight and you get a static instance cut from it — for Cairo, under half the bytes. The two columns are two real requests: family=Cairo:wght@400 and family=Cairo:wght@400;700. The font library's Arabic column is the second shape, so its numbers are the range, not the single weight.

One weight against two, same families, same day
family 400 only 400 + 700 Latin, 400 only
Cairo 13 30 15
Tajawal 9 9 10
Noto Naskh Arabic 51 92 11
Noto Sans Arabic 48 162 10
Amiri 106 106 19
IBM Plex Sans Arabic 42 42 19

The last two rows did not move because those families ship static weights: one file per weight either way. Of the 57, 30 serve the identical file for 400 and 700, which is how you can tell a variable family from a static one without asking.

So the practical rule is dull: request the weights you actually use. A page that sets Arabic body text at one weight should ask for one weight.

What the visitor actually downloads

Google splits each family into unicode-range subsets, and a browser only fetches the ranges the page's characters fall into. An Arabic page loads the Arabic file; a Latin visitor to the same page loads the Latin file and never touches the Arabic one. The number that matters is the subset your reader needs, not the total in the CSS.

pyftsubset Cairo-Regular.ttf   --unicodes="U+0600-06FF,U+0750-077F,U+200C-200D,U+0020-007E"   --layout-features="kern,liga,calt,init,medi,fina,rlig"   --flavor=woff2 --output-file=cairo-subset.woff2

Two things go wrong with aggressive subsetting. Dropping U+200C and U+200D breaks joining behaviour in copied text, and dropping vocalisation marks (U+064B–U+0652) makes any diacriticised content render from a fallback font mid-sentence.

The four things worth doing

  1. Measure your family before you commit to it, at the weight you will ship.
  2. Request only the weights you use, so you are not paying for an axis you ignore.
  3. Preload only the subset the first screen needs, and only if the page is in that language.
  4. Keep font-display: swap and unicode-range on the face, so a Latin-only reader never waits on Arabic.

The numbers above come from the webfont cost tool, which fetches and counts the files in your browser rather than quoting a table. The library lists all 57 with their measured sizes.

Sources

  • W3C Arabic Layout Requirements §7.4 — Arabic ascenders and descenders extend much further than Latin, which is part of why the file and the leading both differ.
  • Measured from fonts.googleapis.com/css2 and the WOFF2 files it names, 2026-10-26, 57 families shipping an Arabic subset. The table above is rendered from src/data/fonts.json, which scripts/fetch-library.mjs regenerates.

Measure a family Browse the library