Letras Diferentes
Unicode research · font distribution and CSS

CSS unicode-range and Font Subsetting: Coverage, Loading and Risks

Explain CSS @font-face unicode-range, actual font glyph coverage, webfont subsetting strategies and failure modes for combining marks, emoji and script shaping.

Technical referenceStandards-aware implementation guide

A CSS unicode-range descriptor is a declaration about when a font face is relevant for character matching. It is not a tool that cuts bytes out of a font file, nor a guarantee that the font supports all declared characters. Reliable subsetting requires coordinated font-file generation, metadata and testing with real script sequences.

Distinguish declared range from actual font content

The unicode-range descriptor restricts which character ranges are considered when selecting a declared @font-face resource. The binary font independently contains a cmap character mapping, outlines, layout lookups and other tables. Advertising U+0400–04FF does not magically add Cyrillic coverage to a file that lacks those glyphs.

Conversely, a subset font may contain only a fraction of the glyphs from its original source, even when the original family name suggests broad language support. Test both the CSS descriptor and binary mapping; a mismatch may cause fallback or boxes where a developer expected a bundled glyph.

Write and audit a basic @font-face rule

A common configuration names a family, points to a WOFF2 file, declares weight/style and supplies a specific range. User agents can avoid downloading fonts that are not relevant to characters used by a page, subject to CSS Fonts loading and selection behavior. Avoid broad claims that every browser loads fonts in the same order.

The descriptor applies to the face's character coverage for matching and fetching; it does not define segmentation, normalization or the meaning of text. HTML language, shaping rules, font fallback and font synthesis still influence output after selecting a face.

Subset more than the visible glyph outlines

Font subsetting tools must preserve appropriate cmap entries, glyph dependencies, composite glyph components and layout information for the intended scripts. For complex scripts, dropping GSUB/GPOS lookups or feature-associated glyphs can produce technically downloadable but visually broken subsets.

A Latin-only subset that accidentally omits mark anchors may display base letters but position combining accents poorly. For Arabic or Indic, reducing glyphs without preserving contextual forms and substitutions can render words incorrectly. Re-test complete words and clusters rather than isolated code points.

Character ranges do not equal linguistic inventories

A language uses combinations of characters and shaping behaviors that are not captured by simple contiguous Unicode blocks. Vietnamese uses Latin base letters and combining diacritics; many languages rely on shared punctuation and Common/Inherited characters. Codepoint sets derived from one sample may omit legitimate user-generated input.

Language-specific distribution should include documented fallback paths. Avoid claiming a subset supports an entire language merely because its most common letters are present; use representative corpus tests plus deliberate edge cases, including pasted text and decomposed sequences.

Combining marks and variation selectors complicate loading

A page can contain U+0065 followed by U+0301, which may require positioning within a font that supports both base and mark. Fragmenting these into separate fonts can impair composition. Emoji presentation selectors (for example U+FE0F) and ZWJ sequences also challenge simple per-codepoint assumptions.

If a declared unicode range excludes variation selectors or combining marks, the font matching behavior and fallback chain can create visually surprising results. Exercise multi-codepoint sequences as single test fixtures to learn how the target browser actually resolves them.

Performance tradeoffs are contextual

Many narrowly split font files can reduce transfer for pages with small inventories, but increase request overhead, CSS complexity, duplicated metadata and maintenance cost. A broader subset can be better for languages with overlapping repertoires. Measure cold and warm loads, transfer bytes, paint behavior and layout shifts in the relevant audience environment.

Preloading resources whose ranges are not needed can defeat demand-driven loading. font-display changes visibility and timing tradeoffs, but does not change Unicode data or ensure correct shaping. Separate performance decisions from typographic correctness checks.

Version and cache the binary artifacts

Font revisions can change Unicode coverage and layout tables while retaining a familiar family name. Cache busting should identify the actual WOFF2 content, and CSS should stay synchronized with the generated subset manifest. Otherwise stale CSS may describe ranges that no longer match deployed files.

Track source font license, origin version, subset tool version, allowed glyph set and output hashes. Before shipping, assert the declared range against actual mappings and run shaping tests on every target script. Do not treat a passing HTTP response as a conformance test.

Validate with a test corpus and real browser traces

Build a specimen corpus containing ASCII, precomposed and decomposed accents, punctuation, Arabic joining, Indic clusters, emoji sequences and mathematical symbols when supported. Inspect network requests and actual font faces used for representative spans. Compare normal text, fallback and missing-glyph behavior.

Success requires more than an unbroken screenshot of the happy path. Confirm expected glyph IDs or images for the hard cases, reasonable line metrics, and intelligible behavior on systems without the optional webfonts. When fonts fail to load, content should remain encoded correctly and accessible.

Reproducible experiment: preserve the input while comparing the output

The following specimen is deliberately small enough to audit manually. For any test involving rendering, also record the exact font files, shaping configuration, user locale and platform versions. The code prints or illustrates source-level facts; it does not claim that JavaScript can identify a platform's selected font or glyph IDs without the relevant layout instrumentation.

@font-face {
  font-family: 'Example Subset';
  src: url('/assets/example-latin.woff2') format('woff2');
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153;
}
/* A descriptor does not add cmap coverage to the actual file. */

A useful report includes both positive and negative evidence. Record what stayed identical as well as what changed: identical scalar values with different glyphs indicate a presentation-layer divergence, whereas differing scalars reveal a transformation, selection or interchange problem. Preserve the original code points before applying normalization or conversion.

Evidence matrix for font distribution and CSS

Layer or specimenControlled observationCorrect interpretation
CSS descriptorunicode-rangecontrols eligibility, not bytes of glyph data
Binary mappingcmapmust actually map needed Unicode scalars
SubstitutionGSUBpreserve relevant script features and dependent glyphs
PositioningGPOSpreserve mark/pair positioning where required
DistributionWOFF2 + cachingtest real request patterns and font-display outcomes

This matrix is a diagnostic aid, not a substitute for conformance testing. Some differences are allowed by Unicode or CSS; others indicate a bug in an implementation, a font, a font-subsetting pipeline or an application that edits text. Be explicit about the relevant standard and the end-user expectation.

Validation protocol for applications and browser integrations

  1. CSS descriptor: Reproduce the observed behavior using unicode-range as a controlled input. Preserve exact source data, capture an expected outcome, and explain whether the measured difference is located in font selection, shaping, layout or copying. The useful observation is controls eligibility, not bytes of glyph data; do not extrapolate from a screenshot alone.
  2. Binary mapping: Reproduce the observed behavior using cmap as a controlled input. Preserve exact source data, capture an expected outcome, and explain whether the measured difference is located in font selection, shaping, layout or copying. The useful observation is must actually map needed Unicode scalars; do not extrapolate from a screenshot alone.
  3. Substitution: Reproduce the observed behavior using GSUB as a controlled input. Preserve exact source data, capture an expected outcome, and explain whether the measured difference is located in font selection, shaping, layout or copying. The useful observation is preserve relevant script features and dependent glyphs; do not extrapolate from a screenshot alone.
  4. Positioning: Reproduce the observed behavior using GPOS as a controlled input. Preserve exact source data, capture an expected outcome, and explain whether the measured difference is located in font selection, shaping, layout or copying. The useful observation is preserve mark/pair positioning where required; do not extrapolate from a screenshot alone.
  5. Distribution: Reproduce the observed behavior using WOFF2 + caching as a controlled input. Preserve exact source data, capture an expected outcome, and explain whether the measured difference is located in font selection, shaping, layout or copying. The useful observation is test real request patterns and font-display outcomes; do not extrapolate from a screenshot alone.

Keep regression fixtures in UTF-8 with explicit scalar annotations when invisible characters, combining sequences or non-BMP characters are present. Test a stable baseline and at least one deliberately adversarial input. Store observed environment data alongside results so later font or browser updates can be interpreted rather than mistaken for content edits.

Failure patterns, false positives and interpretation

  • Overinterpreting css descriptor. A result associated with unicode-range does not, by itself, establish the integrity of the whole text pipeline. controls eligibility, not bytes of glyph data. Compare the input and an independently observed intermediate state before assigning the defect to a component.
  • Overinterpreting binary mapping. A result associated with cmap does not, by itself, establish the integrity of the whole text pipeline. must actually map needed Unicode scalars. Compare the input and an independently observed intermediate state before assigning the defect to a component.
  • Overinterpreting substitution. A result associated with GSUB does not, by itself, establish the integrity of the whole text pipeline. preserve relevant script features and dependent glyphs. Compare the input and an independently observed intermediate state before assigning the defect to a component.
  • Overinterpreting positioning. A result associated with GPOS does not, by itself, establish the integrity of the whole text pipeline. preserve mark/pair positioning where required. Compare the input and an independently observed intermediate state before assigning the defect to a component.
  • Overinterpreting distribution. A result associated with WOFF2 + caching does not, by itself, establish the integrity of the whole text pipeline. test real request patterns and font-display outcomes. Compare the input and an independently observed intermediate state before assigning the defect to a component.

Do not correct a visual artifact by silently rewriting the user's Unicode string, stripping default-ignorable characters without context, replacing unknown scalars with question marks, or flattening rich text without consent. Data integrity, rendering aesthetics, selection behavior and search policy have different constraints. A fix at one layer can create regressions in another.

Standards and primary implementation references

Primary references are linked below. A standard describes normative requirements or terminology, while an implementation manual describes a particular engine. Where behavior is unspecified or depends on fonts and applications, treat observations as environment-specific rather than universal guarantees.

  • W3C CSS Fonts Level 4 — use this normative reference or implementation manual to verify the applicable definitions and requirements for font distribution and CSS. Distinguish what the source specifies from what a particular font or platform happens to implement.
  • MDN: unicode-range descriptor — use this normative reference or implementation manual to verify the applicable definitions and requirements for font distribution and CSS. Distinguish what the source specifies from what a particular font or platform happens to implement.
  • OpenType: cmap table — use this normative reference or implementation manual to verify the applicable definitions and requirements for font distribution and CSS. Distinguish what the source specifies from what a particular font or platform happens to implement.
  • HarfBuzz subset API — use this normative reference or implementation manual to verify the applicable definitions and requirements for font distribution and CSS. Distinguish what the source specifies from what a particular font or platform happens to implement.

This article belongs to the Fonts, Shaping & Text Rendering virtual silo. Related published technical notes explain adjacent layers so the original problem can be isolated without conflating scalar identity, shaping output, font support and editor behavior.

When reproducing a finding, cite the relevant standard, the exact Unicode sequence and the environment in which it occurred. This preserves the value of a technical observation even after browsers, fonts and rendering libraries change.