CSS Fonts and Text: Family, Size, Weight, and Line Height
CSS font properties choose the typeface, size, weight, and line height used to draw text. Text properties adjust spacing, alignment, decoration, and wrapping after the font has been selected. For the broader styling basics, start with the CSS learning guide. This guide is part of our CSS typography and color guide series.
.article {
font-family: system-ui, sans-serif;
font-size: 1rem;
line-height: 1.6;
color: #1f2937;
}
.article h2 {
font-size: 1.75rem;
font-weight: 700;
text-wrap: balance;
} Think of a font stack as a queue of typefaces. The browser checks each option in order for the character and style it needs, then uses the generic family at the end when earlier choices are unavailable.
What Do CSS Font and Text Properties Control?
CSS font-family selects typefaces, font-size sets their scale, and font-weight selects thickness. line-height controls the height of each line box. Then letter-spacing, word-spacing, and text-wrap adjust how text occupies the available line.
Most of these properties inherit, so a body rule can establish readable defaults while headings and controls override only the values that need to differ. That keeps the font queue and its basic measurements consistent across the document.
Build a Font-family Stack
A font-family value is a comma-separated priority list. Quote family names that contain spaces, and always finish with a generic family such as sans-serif, serif, or monospace.
body {
font-family: "Source Sans 3", system-ui, sans-serif;
}
code {
font-family: "IBM Plex Mono", ui-monospace, monospace;
} The browser tries the named web or local font first, then the platform's user-interface font, then any available sans-serif font. Font selection also happens character by character, so later entries can supply glyphs missing from the first family.
A minimal system-font stack can use system-ui, sans-serif. It loads without a font download and suits interface text, but the exact typeface changes with the operating system.
Set Font Size and Line Height
Use rem for most font sizes so text follows the root size. A unitless line-height multiplies each element's own font size, which lets descendants inherit the proportion instead of a fixed measurement.
body {
font-size: 1rem;
line-height: 1.6;
}
h1 {
font-size: 2.25rem;
line-height: 1.15;
} With a 16px root size, body text computes to 16px with a 25.6px line box. The heading computes to 36px with a 41.4px line box. The heading uses a tighter multiplier because large type usually needs less vertical space between lines.
Choose a Font Weight
font-weight accepts keywords such as normal and bold or numbers from 1 to 1000. Common static fonts supply selected values such as 400 and 700, while a variable font may support a continuous range.
.summary {
font-weight: 400;
}
.summary strong {
font-weight: 700;
} Request weights that the loaded font actually provides. If the exact value is missing, the browser chooses an available weight and may synthesize a bold face unless font synthesis is disabled. Two or three intentional weights usually create enough hierarchy for a page.
Adjust Letter and Word Spacing
letter-spacing changes the space between characters, while word-spacing changes the space between words. The initial normal value lets the browser and font use their expected spacing.
.eyebrow {
font-size: 0.875rem;
letter-spacing: 0.04em;
}
.article {
letter-spacing: normal;
word-spacing: normal;
} A small spacing adjustment can suit a short label, but body text should usually keep the font's normal character and word spacing. Large positive or negative values can separate letters from their word shapes or crowd them together.
Control Text Wrapping
The text-wrap shorthand controls soft line wrapping. wrap is the normal behavior, nowrap keeps text on one line and can cause overflow, and balance redistributes short blocks across a limited number of lines. The pretty value asks the browser to favor improved body-copy wrapping.
.card__title {
text-wrap: balance;
}
.card__summary {
text-wrap: pretty;
}
.status-label {
text-wrap: nowrap;
} Use balance for headings rather than long paragraphs. Reserve nowrap for compact content that has a clear overflow plan, since an unbroken label can push beyond a narrow container.
Build a Readable Article Card
Begin with inherited body defaults, then change the title and metadata one property at a time.
body {
font-family: system-ui, sans-serif;
font-size: 1rem;
line-height: 1.6;
}
.article-card {
max-width: 42rem;
}
.article-card__title {
margin: 0;
font-size: 1.75rem;
font-weight: 700;
line-height: 1.2;
text-wrap: balance;
}
.article-card__meta {
font-size: 0.875rem;
color: #4b5563;
} The card inherits the system-font queue and readable body line height. Its title increases size and weight while tightening line height, and the metadata steps down in size without changing the family. A maximum width prevents the text line from stretching across an unrestricted container.
Common Pitfalls & Debugging
A Web Font Briefly Hides Text
Text stays invisible while a font downloads. The chosen font-display strategy includes a block period. Choose an appropriate font-display value so a fallback can appear while the file loads.
@font-face {
font-family: "Article Sans";
src: url("/fonts/article-sans.woff2") format("woff2");
font-display: swap;
} With swap, the browser can show fallback text promptly and replace it when Article Sans becomes available.
The Fallback Font Changes Line Breaks
Text shifts when the web font replaces its fallback. The two fonts have different character widths or vertical metrics. Choose a fallback with similar proportions and test headings, controls, and narrow cards during the swap.
A Fixed Line Height Does Not Scale
Inherited headings look cramped or overlap. A parent supplied a fixed line height such as 24px. Use a unitless value so each descendant multiplies the line height by its own font size.
A System-font Stack Varies by Platform
Text wraps differently on Windows, macOS, and mobile devices. system-ui selects the platform's interface font. Treat platform variation as part of the system-font choice and test the layout with realistic content instead of assuming identical metrics.
Check the Text at Reading Size
Build a dependable font stack, size it with root-relative values, and use unitless line height so text scales with its element. Test fallback metrics anywhere line breaks affect the layout.
Frequently Asked Questions
Does CSS font-weight: bold look the same in every typeface?
CSS font-weight: bold requests weight 700, but that weight looks different across typefaces. If a font lacks the requested weight, the browser uses its font-matching rules or may synthesize a heavier appearance.
What is a good CSS line-height for body text?
A unitless CSS line-height around 1.5 is a useful starting point for body text. Adjust it for the typeface and line length. Headings can often use tighter spacing because their letters are larger and their lines are shorter.
Can CSS letter-spacing use units other than em?
CSS letter-spacing accepts length units such as px, rem, and em. The em unit scales with the element’s own font size, making it a useful choice when letter spacing should grow with the text.
Does text-transform change the underlying text?
CSS text-transform changes how text is displayed, not the underlying text in the document. Copying and assistive-technology behavior can vary, so do not rely on it to change stored values or control how text is announced.
Does text-wrap: balance have consistent browser support?
CSS text-wrap: balance works in current major browsers, but older browsers may ignore it and use normal wrapping. Treat balanced wrapping as an enhancement for headings and short blocks, and check the browsers you support.
Sources
-
[1]
font-family(developer.mozilla.org)
-
[2]
Fundamental text and font styling(developer.mozilla.org)
-
[3]
font-weight(developer.mozilla.org)
-
[4]
line-height(developer.mozilla.org)
-
[5]
letter-spacing(developer.mozilla.org)
-
[6]
word-spacing(developer.mozilla.org)
-
[7]
text-wrap(developer.mozilla.org)
-
[8]
font-display(developer.mozilla.org)
Read Next
Define reusable CSS values with custom properties, var() fallbacks, scoped overrides, theme switching, and computed-value debugging.
Learn CSS typography and color through color formats, length units, font and text properties, custom properties, and shadows.
A decision guide to CSS: whether you still need it with Tailwind and AI, Tailwind or plain CSS, what modern CSS does without JavaScript, how long it takes to be useful, and a roadmap to every CSS guide.