Difficulty: Beginner
Typography is the art and technique of arranging type to make written language legible, readable, and visually appealing. In CSS, font properties control the visual characteristics of text -- which typeface is used, how large it appears, how heavy or light the strokes are, and whether it is styled as italic or oblique. Good typography is arguably the single most impactful design choice on a webpage, since the majority of web content is text.
The font-family property specifies which typeface to use for text. Because you cannot guarantee which fonts are installed on a user's device, CSS uses a font stack -- an ordered list of fonts where the browser uses the first available one. A font stack typically starts with your preferred font, includes one or two similar alternatives, and ends with a generic family keyword (serif, sans-serif, monospace, cursive, or fantasy). The generic family is the ultimate fallback -- every browser has at least one font for each generic family.
The font-size property sets the size of the text. It accepts various units: pixels (px) provide fixed sizes, em is relative to the parent element's font size, rem is relative to the root element's font size, percentages are relative to the parent, and viewport units (vw, vh) scale with the browser window. In modern CSS, rem is the preferred unit for font sizes because it provides consistency across the page while respecting the user's browser font-size preferences. A base of 1rem equals the root font size, which is typically 16px by default.
The font-weight property controls the thickness of the text strokes. It accepts keyword values (normal, bold, lighter, bolder) or numeric values from 100 to 900 in increments of 100. Normal text is weight 400, bold is 700. Variable fonts can support any weight value, not just the 100-increment steps. The availability of specific weights depends on whether the font file includes them -- requesting weight 300 on a font that only includes 400 and 700 will cause the browser to fall back to the nearest available weight.
The font-style property controls whether text is displayed normally, in italic, or in oblique form. Italic text uses a specially designed italic version of the typeface (with different letterforms), while oblique text is simply the normal text slanted. Most fonts include a true italic variant. The font shorthand combines family, size, weight, style, line-height, and variant in a single declaration, though it is less common in modern CSS because its syntax is strict and error-prone.
/* System font stack (modern best practice) */
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI",
Roboto, Oxygen, Ubuntu, Cantarell,
"Helvetica Neue", sans-serif;
}
/* Serif font stack */
.article-body {
font-family: Georgia, "Times New Roman", Times, serif;
}
/* Monospace font stack (for code) */
code, pre {
font-family: "Fira Code", "JetBrains Mono", Consolas,
"Courier New", monospace;
}
/* Font name with spaces must be quoted */
.heading {
font-family: "Playfair Display", Georgia, serif;
}
Font stacks provide fallback options. The system font stack uses each operating system's native UI font for the fastest possible rendering. Always end with a generic family (sans-serif, serif, monospace). Font names containing spaces must be wrapped in quotes.
/* Pixels: fixed size, does not respect user preferences */
.px-text {
font-size: 16px;
}
/* rem: relative to root (html) font-size -- RECOMMENDED */
.rem-text {
font-size: 1rem; /* typically 16px */
}
.rem-large {
font-size: 1.5rem; /* typically 24px */
}
/* em: relative to parent's font-size */
.parent {
font-size: 20px;
}
.child {
font-size: 0.8em; /* 20px * 0.8 = 16px */
}
/* Responsive: clamp for fluid typography */
.fluid-heading {
font-size: clamp(1.5rem, 4vw, 3rem);
/* Min: 1.5rem, Preferred: 4vw, Max: 3rem */
}
Use rem for consistent sizing that respects user preferences. Em is useful for component-internal scaling. The clamp() function creates fluid typography that scales smoothly between a minimum and maximum size based on viewport width.
/* Keyword weights */
.normal { font-weight: normal; } /* same as 400 */
.bold { font-weight: bold; } /* same as 700 */
.lighter { font-weight: lighter; } /* one step lighter than parent */
.bolder { font-weight: bolder; } /* one step bolder than parent */
/* Numeric weights */
.thin { font-weight: 100; }
.light { font-weight: 300; }
.regular { font-weight: 400; }
.medium { font-weight: 500; }
.semibold { font-weight: 600; }
.bold-num { font-weight: 700; }
.extrabold { font-weight: 800; }
.black { font-weight: 900; }
/* Font style */
.italic { font-style: italic; }
.oblique { font-style: oblique; }
.normal-style { font-style: normal; }
Numeric weights give precise control. 400 is normal, 700 is bold. Not all fonts support all weights -- if a weight is unavailable, the browser selects the nearest available. Italic uses a specially designed variant; oblique is a computed slant of the normal style.
/* Font shorthand: style weight size/line-height family */
.shorthand {
font: italic 700 1.25rem/1.6 Georgia, serif;
}
/* Equivalent longhand */
.longhand {
font-style: italic;
font-weight: 700;
font-size: 1.25rem;
line-height: 1.6;
font-family: Georgia, serif;
}
/* Minimum required: size and family */
.minimal {
font: 1rem sans-serif;
}
/* System font keyword */
.system {
font: menu; /* uses the OS menu font */
}
The font shorthand requires at minimum font-size and font-family. The order matters: style and weight must come before size, and family must be last. line-height is specified with a slash after size. While concise, the shorthand resets all omitted properties to their defaults, which can cause unexpected changes.
font-family, font-size, font-weight, font-style, Font Stacks, System Fonts