Creator Glow Lab by MissMacknOG

Typography Dictionary

Understand type scales, font loading, font stacks, pairing, hierarchy, micro-typography, and responsive web type with clear explanations and practical tips.

Type scales, loading, and hierarchy

Learn how modular scales, fluid type, font loading, pairing, micro-typography, font stacks, and responsive typography work together in a readable interface.

Putting typographic principles into practice

Explore the reference explanations and tips below, then use the interactive examples to examine type treatments. Font Pairing Studio provides complementary heading and body combinations.

Modular Scale

Type Scales

A modular scale is a series of sizes that share a ratio. The most common ratio is 1.25 (Major Third). Starting from a base of 1rem, each step multiplies by the ratio — so you get 1rem, 1.25rem, 1.563rem, 1.953rem, and so on. This creates visual harmony: every font size on your page is mathematically related.

Use a ratio of 1.25 for content-heavy sites (tight scale) and 1.5 for large-screen editorial designs (wide scale). Never pick font sizes arbitrarily — the visual coherence comes from the ratio.

Fluid Typography with clamp()

Type Scales

clamp(min, preferred, max) lets a font size scale smoothly between a minimum and maximum based on the viewport width — no media queries needed. The preferred value uses a viewport unit (vw) plus a small fixed value to prevent text from shrinking to nothing on tiny screens.

The formula for the preferred value is: calc(Xvw + Yrem) where Y is a small offset (0.25–0.5rem) that prevents the text from scaling to zero. Use a tool like utopia.fyi to generate precise clamp() values.

Display & Hero Type

Type Scales

Display type lives above your normal scale — 5rem to 10rem or larger. At these sizes, normal body tracking and weight become wrong: display type needs tighter letter-spacing (negative values), reduced line-height (often below 1.0 on very large text), and usually heavier weight. Treat display headings as graphic elements, not just large text.

Negative letter-spacing on display type is not optional — at 6rem+ the default tracking (0) looks loose and amateurish. Start at -0.03em and increase the tightness as the size grows.

Named Size Tokens

Type Scales

Instead of hardcoding pixel values throughout your CSS, define all type sizes as named tokens in :root. This makes the whole scale editable from one place — change --text-base from 16px to 18px and every element that uses the scale updates automatically.

If you're using Tailwind CSS, its type scale already follows this token pattern. For hand-rolled CSS, define these in :root alongside your color tokens — they form the typographic foundation of your design system.

Google Fonts (@import)

Font Loading

Google Fonts provides free, high-quality web fonts. Import one URL that loads multiple weights and styles. Always use &display=swap to prevent text from being invisible while the font loads — the browser renders fallback text immediately, then swaps to the web font when it arrives.

Prefer <link rel='preconnect'> over @import for performance — it starts the connection earlier. For critical fonts (body text), also add rel='preload' to eliminate the render-blocking delay completely.

Self-Hosted @font-face

Font Loading

Hosting fonts on your own server removes dependency on Google's CDN and gives you full control over caching, subsetting, and privacy. Use WOFF2 (best compression, all modern browsers). Always provide the WOFF2 format — it's universally supported and up to 30% smaller than WOFF.

Use cloudconvert.com or Fonttools to subset your fonts — remove characters you won't use. A full Latin subset can drop from 200KB to 30KB. Always include unicode-range if serving multiple subsets.

Variable Fonts

Font Loading

A single variable font file contains the entire weight (and sometimes width/slant) range — replacing multiple @font-face declarations. Instead of loading separate files for 400, 500, 600, 700, you load one file and animate between any weight value, including decimals. Inter, Roboto Flex, and Recursive are popular variable fonts.

Check variablefonts.io for a gallery of free variable fonts. Google Fonts now serves most popular fonts as variable files automatically when you request multiple weights — no extra work needed.

Serif + Sans-Serif Pairing

Pairing & Hierarchy

The most reliable pairing in typography: a serif for headings and display text, a sans-serif for body copy. Serifs (letters with foot strokes) feel authoritative, editorial, and timeless. Sans-serifs feel clean, modern, and legible at small sizes. The visual contrast between the two creates a clear hierarchy without relying on size alone.

When pairing, choose fonts with different personalities but similar proportions. Avoid pairing two serifs or two sans-serifs — the difference is too subtle to create hierarchy. One designer rule: 'Contrast, not conflict.'

Weight Contrast for Hierarchy

Pairing & Hierarchy

Font weight is the most powerful typographic hierarchy tool after size. A bold heading (700-900) next to regular body text (400) creates instant visual separation. Avoid using font sizes alone to create hierarchy — weight contrast does it more elegantly and takes up less space.

Limit yourself to three weight layers per page: heavy (600-800) for headings, regular (400) for body, and a subtle light or medium for captions. More than three weights usually creates noise rather than hierarchy.

All-Caps Labels with Tracking

Pairing & Hierarchy

Short text set in all-capitals with generous letter-spacing (tracking) is one of the most effective typographic tools in luxury and creator design. It reads as a label or category marker — subordinate to headings but authoritative in its own right. Always reduce the font size when using all-caps; capitals are optically larger than lowercase at the same px value.

Never use all-caps for long text — readability drops sharply after 3-4 words. Keep all-caps labels to 5 words maximum. Add tracking of at least 0.15em; without it, all-caps text looks cramped.

Heading-to-Body Size Ratio

Pairing & Hierarchy

The visual relationship between your heading and body text sizes determines how clearly hierarchy reads at a glance. A heading should be at least 2× the body size to register as a heading. Below that ratio, the page feels flat. For hero headings, 3–5× the body size creates a commanding visual anchor.

On mobile the ratio naturally compresses because viewport width limits the hero size. This is expected — design for desktop hierarchy first, then verify mobile doesn't collapse the ratio below 1.8×.

Line Height (Leading)

Micro-Typography

Line height controls the vertical space between lines of text. Body copy needs more breathing room (1.6–1.8) because the eye must travel back to find the next line. Headings need tighter leading (1.0–1.2) because they're read as a unit, not line by line. Unitless values (like 1.6) scale proportionally with font size — always prefer them over px or rem values for line-height.

Line height and font size work together — large text needs less line height, small text needs more. A 72px hero heading at 1.75 line height would have 126px between lines, which is absurd. Always match line-height to the role of the text.

Letter Spacing (Tracking)

Micro-Typography

Letter spacing affects how text feels: tight tracking (negative values) reads as premium and bold; loose tracking reads as elegant on labels and captions. The key rule: tighten as text gets bigger, loosen as it gets smaller. A 72px headline should have -0.04em or more. Body text at 16px should be 0 or barely adjusted. Small all-caps labels should have +0.15em or more.

Photoshop and Figma measure tracking in thousandths of an em (so '–30' in Figma = -0.030em in CSS). When implementing designs from Figma, divide the tracking value by 1000 to get the CSS em value.

Readable Line Width (Measure)

Micro-Typography

The 'measure' is the width of a column of text. Research on readability consistently shows 50–75 characters per line is optimal. Too wide and the eye gets lost finding the next line. Too narrow and the eye must turn back too frequently. The ch unit measures one character width — making max-width: 65ch almost magical for body text.

text-wrap: balance is a modern CSS property that distributes text evenly across lines, eliminating the 'last line with one word' problem on headings. It's now supported in all modern browsers and dramatically improves heading aesthetics.

Font Smoothing & Rendering

Micro-Typography

Browsers render fonts differently on each operating system. macOS uses subpixel rendering by default, which can make fonts look thick and heavy. Adding -webkit-font-smoothing: antialiased forces lighter, thinner rendering — the look used in almost every premium web design. On dark backgrounds especially, this makes a significant visual difference.

antialiased rendering makes text thinner and lighter, which looks premium on dark backgrounds but can reduce legibility of very small text (below 12px) on light backgrounds. Apply globally on dark-themed sites, selectively on mixed-theme sites.

System UI Stack

Font Stacks

System UI fonts are the native fonts of each operating system — San Francisco on Apple devices, Segoe UI on Windows, Roboto on Android. Using the system stack means zero network requests, zero layout shift, and a font that looks at home on the user's device. Perfect for UI elements, dashboards, and apps where speed matters more than brand personality.

system-ui alone is sufficient in 2024+ — all modern browsers understand it. The longer stack is there for older browsers. If you want zero web font downloads but a richer feel, use system-ui with a line-height of 1.5 and letter-spacing of -0.01em.

Serif Stack

Font Stacks

When you want a serif look without a web font download, use the system serif stack. Georgia and Times New Roman are universally available and readable. For a modern, editorial feel, the 'ui-serif' keyword selects the system's best serif font (Charter on macOS, for example) before falling back to Georgia.

ui-serif was added to CSS Fonts Level 4 and gives you the OS's preferred serif font, which is often higher quality than Georgia. Use it as the first value, with Georgia as a solid fallback. Supported in all modern browsers.

Monospace Stack

Font Stacks

Monospace fonts are used for code, terminals, labels, and technical content. Every character has the same width, making code align perfectly in columns. ui-monospace selects the OS best monospace (SF Mono on macOS). For a more expressive developer-aesthetic, Space Mono or Fira Code add personality.

Using a monospace font for UI labels and data tables — even for non-code content — creates a technical, precision aesthetic. This is used extensively in finance apps, terminals, and developer tools. Pair with tight letter-spacing (0.02em) for best results.

Contrast on Dark Backgrounds

Dark Interfaces

Pure white (#ffffff) on pure black (#000000) creates harsh, high-contrast text that strains eyes in low-light environments. Premium dark interfaces use off-white text (#f4f4f5, #e4e4e7) on very dark gray (#09090b, #0a0a0f). Use RGBA opacity for hierarchy: 100% for primary text, 70% for secondary, 40% for muted, and 20% for placeholders.

WCAG AA requires a 4.5:1 contrast ratio for body text. Use the WebAIM Contrast Checker to verify your text/background pairs. Off-white (#f4f4f5) on dark charcoal (#0a0a0f) has a contrast ratio of ~17:1 — well above the requirement.

Glow-Enhanced Text

Dark Interfaces

On dark backgrounds, text-shadow with a matching color creates a soft luminous halo around text. This simulates the way light sources bleed at their edges — making text feel backlit rather than printed. Use subtle values for body text and bold values for hero headings or accent elements. Always match the glow color to your brand accent.

Stack 2–4 text-shadow values with increasing blur and decreasing opacity for realistic glow depth. The inner shadow (smallest blur, highest opacity) defines the core; the outer layers define the atmospheric reach. Use the Studio's Glow Text Builder to tune these interactively.

Font Weight on Dark Backgrounds

Dark Interfaces

Light text on a dark background requires lighter font weights than equivalent text on a light background. A font-weight of 400 on white might need to drop to 300 on black to achieve the same visual heaviness. Conversely, antialiased rendering on dark surfaces makes bold text look crisper and sharper — you can often push to 700-800 for headings without them feeling heavy.

If your font supports it, use font-weight: 350 (between Light and Regular) for dark-background body copy. This requires a variable font. It's the weight that reads as 'normal' on dark without the thinness of 300 or the heaviness of 400 against black.

The clamp() Formula Explained

Responsive Type

clamp(MIN, PREFERRED, MAX) takes three arguments. MIN is the smallest the text will ever be. MAX is the largest it will grow. PREFERRED is the live calculation — usually a viewport width unit plus a fixed offset. The offset prevents the text from scaling to zero at tiny viewports. The formula: PREFERRED = (MAX - MIN) / (MAX_VP - MIN_VP) * 100vw + (MIN - PREFERRED_AT_MIN_VP).

Visit utopia.fyi/type/calculator to generate precise clamp() values between your min/max viewport and min/max size. Paste the output directly into your CSS. The calculator handles the math so you don't have to.

Viewport-Relative Units for Text

Responsive Type

vw (viewport width), svh (small viewport height), and dvh (dynamic viewport height) let text respond to the screen dimensions. Pure vw-based font sizes work well for large display text but scale too dramatically alone — always combine vw with a fixed rem unit inside calc() or clamp() to maintain a floor. Never set body text in pure vw.

Use svh (small viewport height) instead of vh for full-screen sections on mobile. Regular 100vh includes the browser chrome, causing content to be hidden behind the address bar. svh gives you the reliably visible portion.

text-wrap: balance & pretty

Responsive Type

CSS text-wrap: balance distributes text evenly across multiple lines — eliminating the orphaned single word on the last line that plagues headings. text-wrap: pretty applies more sophisticated line-breaking to prevent widows and orphans in body copy. Both are now supported in Chrome, Safari, and Firefox and require no JavaScript.

text-wrap: balance can be applied globally to all headings without performance concerns — browsers only apply it to text under ~6 lines. Pair with max-width: 30ch on headings for best results on mobile.

font-display: swap

Performance

By default, browsers block text rendering until a web font loads — this creates a flash of invisible text (FOIT). font-display: swap tells the browser to immediately show text using the fallback font, then swap to the web font when it arrives. This eliminates invisible text at the cost of a visible layout shift (FOUT). For most sites, swap is the best trade-off.

To minimize the flash of unstyled text (FOUT), use font-size-adjust and ascent-override to make your fallback font match the web font's metrics. Modern browsers support @font-face overrides to do this precisely.

Preconnect for External Fonts

Performance

When loading fonts from Google Fonts or Typekit, the browser must establish a connection to an external server before any font data can download. Adding rel='preconnect' <link> tags in your <head> tells the browser to start that connection immediately — before it even parses your stylesheet. This saves 200–500ms on first load.

To find the preload URL for a specific font weight, open Chrome DevTools → Network tab → filter by 'font' → load the page → copy the woff2 request URL. Use this for your single most-used font weight (usually the 400 body weight).

Font Subsetting & unicode-range

Performance

A full font file includes characters for every language it supports — often 500-2000+ glyphs. If your site is English-only, you need perhaps 200 glyphs. Subsetting removes the rest, shrinking file size by 60-80%. Google Fonts does this automatically via text= parameter. For self-hosted fonts, use Fonttools or glyphhanger CLI to generate subsets.

For English-only sites using Google Fonts, add &subset=latin to your import URL or use Glyphhanger (npm install -g glyphhanger) to analyze your pages and generate a custom subset with only the glyphs actually used.