Typography
Apple's typographic system — from Display to Caption. Every size, weight, and spacing decision that gives interfaces their voice.
Type Scale
Twelve carefully calibrated levels — each optimized for its context. Sizes map directly to Apple's SF Pro optical sizing ranges.
Font Weights
SF Pro exposes four distinct weights used across the system. Each carries semantic meaning — weight communicates emphasis before content is read.
Hierarchy in Practice
A real-world card demonstrating all four levels of the type hierarchy working in concert — from eyebrow label to metadata.
Building with Purpose
Typography creates hierarchy before a single word is read. Size, weight, and spacing work together to guide the eye through content in a natural, effortless flow.
Line Length & Legibility
Optimal reading measure sits between 60–80 characters per line. Too narrow creates choppy rhythm; too wide loses the reader's place on return.
max-width: 65ch or 672px on body text containers to enforce optimal measure.Optical Sizing
SF Pro automatically adjusts letterform details based on point size. Display variants have finer strokes and tighter proportions; Text variants are optimized for readability at small sizes.
Code: Implementing the Scale
Production-ready CSS custom properties and a reusable React component for consuming the type system.
/* Typography Scale CSS Variables */ :root { /* Typeface */ --font-sans: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text", "Helvetica Neue", Arial, sans-serif; --font-mono: "SF Mono", "Fira Code", monospace; /* Type Scale */ --text-display: 56px; /* Hero, landing pages */ --text-large-title: 40px; /* Page titles */ --text-title1: 32px; /* Section headings */ --text-title2: 26px; /* Card titles */ --text-title3: 22px; /* Grouped list headers */ --text-headline: 17px; /* Bold emphasis (600) */ --text-body: 17px; /* Primary reading (400) */ --text-callout: 16px; /* Callout descriptions */ --text-subhead: 15px; /* Secondary labels */ --text-footnote: 13px; /* Supplemental notes */ --text-caption: 12px; /* Captions, timestamps */ /* Font Weights */ --weight-regular: 400; --weight-medium: 500; --weight-semibold: 600; --weight-bold: 700; /* Line Heights */ --leading-tight: 1.1; --leading-snug: 1.25; --leading-normal: 1.5; --leading-relaxed: 1.6; }
import React from 'react'; type Variant = | 'display' | 'large-title' | 'title1' | 'title2' | 'title3' | 'headline' | 'body' | 'callout' | 'subhead' | 'footnote' | 'caption'; const variantStyles: Record<Variant, React.CSSProperties> = { 'display': { fontSize: '56px', fontWeight: 700, letterSpacing: '-0.03em', lineHeight: 1.05 }, 'large-title':{ fontSize: '40px', fontWeight: 700, letterSpacing: '-0.02em', lineHeight: 1.1 }, 'title1': { fontSize: '32px', fontWeight: 700, letterSpacing: '-0.02em', lineHeight: 1.15 }, 'title2': { fontSize: '26px', fontWeight: 700, letterSpacing: '-0.01em', lineHeight: 1.2 }, 'title3': { fontSize: '22px', fontWeight: 600, letterSpacing: '0', lineHeight: 1.25 }, 'headline': { fontSize: '17px', fontWeight: 600, letterSpacing: '0', lineHeight: 1.35 }, 'body': { fontSize: '17px', fontWeight: 400, letterSpacing: '0', lineHeight: 1.55 }, 'callout': { fontSize: '16px', fontWeight: 400, letterSpacing: '0', lineHeight: 1.55 }, 'subhead': { fontSize: '15px', fontWeight: 400, letterSpacing: '0', lineHeight: 1.55 }, 'footnote': { fontSize: '13px', fontWeight: 400, letterSpacing: '0', lineHeight: 1.55 }, 'caption': { fontSize: '12px', fontWeight: 400, letterSpacing: '0.01em', lineHeight: 1.5 }, }; interface TypeTextProps { as?: keyof JSX.IntrinsicElements; variant?: Variant; color?: 'primary' | 'secondary' | 'tertiary' | 'accent'; children: React.ReactNode; style?: React.CSSProperties; className?: string; } const TypeText = ({ as: Tag = 'p', variant = 'body', color = 'primary', children, style, className, }: TypeTextProps) => { const colorVar = { primary: 'var(--color-text-primary)', secondary: 'var(--color-text-secondary)', tertiary: 'var(--color-text-tertiary)', accent: 'var(--color-accent)', }[color]; return ( <Tag className={className} style={{ fontFamily: 'var(--font-sans)', color: colorVar, margin: 0, ...variantStyles[variant], ...style, }} > {children} </Tag> ); }; export default TypeText;
Rules & Best Practices
Eight practical guidelines derived from Apple HIG. Each pair contrasts correct and incorrect application.
Numbers & Data
Use tabular figures for data that must align vertically. SF Pro supports tabular-nums via font-feature-settings, ensuring digits share identical advance widths.
font-variant-numeric: tabular-nums; font-feature-settings: "tnum";
Practical Web Scale
Ready-to-use pixel and rem values for web implementations. All values align to the 8pt grid and SF Pro's optical sizing boundaries.