The Art and Science of Text on the Web
Welcome to our exploration of text styling and typography in CSS! Typography is the art and technique of arranging type to make written language legible, readable, and appealing when displayed. On the web, typography is a critical component of user experience and brand identity.
Text is the primary vehicle for delivering content on the web. How you style and present that text can dramatically impact how users perceive, understand, and interact with your site. Today, we'll dive into the CSS properties that control typography and learn how to craft text that is both beautiful and functional.
File Organization
For today's session, we'll use the following files:
- CSS File:
styles/typography.cssin your styles folder - HTML File:
typography_examples.htmlin your project root
Make sure to create these files and link them properly before we begin the exercises.
Typography Fundamentals
Before diving into CSS properties, let's establish some fundamental typographic concepts that will inform our design decisions.
Typeface vs. Font
While often used interchangeably, these terms have distinct meanings:
- Typeface: A collection of fonts designed with common visual characteristics (e.g., Helvetica, Times New Roman, Georgia)
- Font: A specific weight, width, and style of a typeface (e.g., Helvetica Bold Italic, Times New Roman Regular)
Analogy: If a typeface is like a music album, a font is like an individual song within that album.
Type Classifications
Typefaces generally fall into several categories:
- Serif: Fonts with small decorative lines (serifs) at the ends of character strokes. Examples include Times New Roman, Georgia, and Baskerville.
- Sans-serif: Fonts without serifs, featuring clean, simple lines. Examples include Arial, Helvetica, and Roboto.
- Monospace: Fonts where each character occupies the same width. Examples include Courier, Consolas, and Roboto Mono.
- Display: Decorative fonts designed for headlines and short text. Examples include Impact, Bangers, and Playfair Display.
- Script: Fonts that mimic handwriting or calligraphy. Examples include Brush Script, Pacifico, and Dancing Script.
Typographic Hierarchy
Hierarchy refers to the arrangement of elements to show their order of importance. In typography, this is achieved through:
- Size: Larger text draws more attention
- Weight: Bolder text stands out
- Style: Italic or different fonts create contrast
- Color: Different colors emphasize different elements
- Spacing: How text is arranged affects its prominence
Real-world example: Think of a newspaper front page. The main headline is large and bold, sub-headlines are smaller but still prominent, and body text is the smallest. This visual hierarchy guides readers through the content in order of importance.
Readability vs. Legibility
- Legibility: How easily individual characters can be distinguished from one another (a property of the typeface design)
- Readability: How easily words, sentences, and paragraphs can be read (influenced by typographic choices like spacing, line length, etc.)
Both factors are essential for effective web typography.
CSS Font Properties
Let's explore the core CSS properties for controlling fonts.
font-family
The font-family property specifies the typeface to use for text.
/* Font family examples */
body {
font-family: Arial, Helvetica, sans-serif;
}
h1, h2, h3 {
font-family: 'Georgia', 'Times New Roman', serif;
}
code {
font-family: 'Courier New', Courier, monospace;
}
Font stacks: Notice how we provide multiple font options in a comma-separated list. The browser will use the first available font on the user's system. This creates a "fallback system" known as a font stack.
Generic font families: The last value in each stack is a generic family (serif, sans-serif, monospace, etc.) that ensures the browser will display something appropriate even if none of the specific fonts are available.
font-size
The font-size property sets the size of the text.
/* Font size examples */
body {
font-size: 16px; /* Base font size for the document */
}
h1 {
font-size: 2.5rem; /* 2.5 times the root element font size */
}
h2 {
font-size: 2rem;
}
h3 {
font-size: 1.5rem;
}
.small-text {
font-size: 0.8rem;
}
.large-text {
font-size: 1.2rem;
}
CSS Size Units
Different units can be used for font sizing:
- px (pixels): Fixed-size units, doesn't scale with user preferences
p { font-size: 16px; } - em: Relative to the parent element's font size
/* If parent has font-size: 16px */ .child { font-size: 1.5em; } /* = 24px */ - rem (root em): Relative to the root element's font size (typically the html element)
/* If html has font-size: 16px */ h1 { font-size: 2rem; } /* = 32px */ - % (percent): Relative to the parent element's font size
/* If parent has font-size: 16px */ .child { font-size: 150%; } /* = 24px */ - vw (viewport width): Relative to 1% of the viewport's width
h1 { font-size: 5vw; } /* 5% of viewport width */
Best practice: For responsive typography, use relative units (rem, em) instead of fixed units (px). This allows text to scale based on user preferences and device characteristics.
font-weight
The font-weight property sets the thickness of characters.
/* Font weight examples */
body {
font-weight: normal; /* or 400 */
}
h1, h2, h3 {
font-weight: bold; /* or 700 */
}
.light-text {
font-weight: 300;
}
.medium-text {
font-weight: 500;
}
.extra-bold {
font-weight: 800;
}
Numeric values: Font weights can be specified with numeric values from 100 to 900, in increments of 100.
- 100: Thin (Hairline)
- 200: Extra Light (Ultra Light)
- 300: Light
- 400: Normal (Regular)
- 500: Medium
- 600: Semi Bold (Demi Bold)
- 700: Bold
- 800: Extra Bold (Ultra Bold)
- 900: Black (Heavy)
Note: Not all fonts provide all weight variants. If a specified weight isn't available, the browser will use the closest available weight.
font-style
The font-style property sets whether text is italic or normal.
/* Font style examples */
p {
font-style: normal;
}
em {
font-style: italic;
}
.slanted-text {
font-style: oblique;
}
Note: italic uses a specifically designed italic version of the font if available, while oblique simply slants the normal version. In practice, the difference is often minimal.
font-variant
The font-variant property enables special font forms.
/* Font variant examples */
.small-caps {
font-variant: small-caps;
}
.normal-text {
font-variant: normal;
}
small-caps: Transforms lowercase letters into smaller uppercase letters, creating an elegant look for headings or emphasis.
font (shorthand)
The font shorthand property sets multiple font properties at once.
/* Font shorthand syntax */
/* font: font-style font-variant font-weight font-size/line-height font-family */
h1 {
font: italic small-caps bold 2rem/1.2 'Georgia', serif;
}
p {
font: normal 1rem/1.6 'Arial', sans-serif;
}
Note: When using the font shorthand, font-size and font-family are required. All other properties are optional and will reset to their default values if omitted.
Text Styling Properties
Beyond font properties, CSS offers many ways to control the appearance and behavior of text.
color
The color property sets the color of text.
/* Text color examples */
body {
color: #333; /* Dark gray */
}
h1 {
color: #0066cc; /* Blue */
}
.error-text {
color: #cc0000; /* Red */
}
.subtle-text {
color: rgba(0, 0, 0, 0.6); /* Semi-transparent black */
}
Note: For color syntax details, refer to our earlier session on Colors, Backgrounds, and Borders.
text-align
The text-align property sets the horizontal alignment of text within its container.
/* Text alignment examples */
p {
text-align: left; /* Default for LTR languages */
}
h1, h2 {
text-align: center;
}
.quote {
text-align: right;
}
.full-paragraph {
text-align: justify; /* Spreads text evenly between the margins */
}
Justify caution: While justify creates clean edges, it can create inconsistent spacing between words and reduce readability, especially with narrow columns. Use with caution.
text-decoration
The text-decoration property adds or removes lines on text.
/* Text decoration examples */
a {
text-decoration: underline;
}
a:hover {
text-decoration: none; /* Removes underline on hover */
}
h2 {
text-decoration: underline dotted; /* Dotted underline */
}
.strikethrough {
text-decoration: line-through;
}
.fancy-title {
text-decoration: underline overline #ff3028; /* Multiple decorations with color */
}
Modern properties: Text decoration can be further controlled with:
text-decoration-line: sets the type of line (underline, overline, line-through)text-decoration-style: sets the style of the line (solid, dotted, dashed, etc.)text-decoration-color: sets the color of the linetext-decoration-thickness: sets the thickness of the line
text-transform
The text-transform property controls text capitalization.
/* Text transformation examples */
.uppercase {
text-transform: uppercase; /* ALL CAPS */
}
.lowercase {
text-transform: lowercase; /* all lowercase */
}
.capitalize {
text-transform: capitalize; /* First Letter Of Each Word */
}
.preserve {
text-transform: none; /* Preserves the original case */
}
Accessibility note: Using text-transform is preferable to typing text in all caps in your HTML, as screen readers may interpret text in all caps as acronyms and read them letter by letter.
text-indent
The text-indent property sets the indentation of the first line of a block of text.
/* Text indent examples */
p {
text-indent: 2em; /* Indents first line by 2em */
}
.hanging-indent {
text-indent: -2em;
padding-left: 2em; /* Prevent overflow to the left */
}
Use cases: Traditional paragraph indentation, hanging indents for bibliographies or reference lists
text-shadow
The text-shadow property adds shadow effects to text.
/* Text shadow examples */
.subtle-shadow {
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.2);
}
.glow-effect {
text-shadow: 0 0 5px #fff, 0 0 10px #fff, 0 0 15px #0073e6;
}
.three-d-effect {
text-shadow: 1px 1px 0 #ddd, 2px 2px 0 #c8c8c8, 3px 3px 0 #bbb;
}
Syntax: text-shadow: horizontal-offset vertical-offset blur-radius color
Multiple shadows: Separate multiple shadow declarations with commas to create complex effects.
Performance note: Multiple text shadows can impact rendering performance, especially on text-heavy pages or low-powered devices.
white-space
The white-space property controls how whitespace within an element is handled.
/* White space examples */
.normal-wrap {
white-space: normal; /* Default: collapses whitespace, wraps text */
}
.no-wrap {
white-space: nowrap; /* Prevents text from wrapping to a new line */
}
.preserve-whitespace {
white-space: pre; /* Preserves whitespace like the HTML <pre> tag */
}
.preserve-wrap {
white-space: pre-wrap; /* Preserves whitespace but allows wrapping */
}
.collapse-preserve {
white-space: pre-line; /* Collapses spaces but preserves line breaks */
}
word-wrap and overflow-wrap
These properties control whether long words can be broken to prevent overflow.
/* Word wrap examples */
.break-words {
word-wrap: break-word; /* Legacy name */
overflow-wrap: break-word; /* Modern name, same function */
}
.anywhere {
overflow-wrap: anywhere; /* May break in the middle of words without hyphens */
}
.normal-wrap {
overflow-wrap: normal; /* Only breaks at allowed break points */
}
Use case: Handling long URLs, email addresses, or unbroken strings that might overflow containers
word-break
The word-break property specifies where words should break if they are too long.
/* Word break examples */
.break-all {
word-break: break-all; /* May break between any two letters */
}
.break-word {
word-break: break-word; /* Try to break at word boundaries first */
}
.keep-all {
word-break: keep-all; /* Don't break words unless at normal hyphenation points */
}
Note: word-break: break-word is being phased out in favor of overflow-wrap: break-word.
letter-spacing
The letter-spacing property adjusts the space between characters.
/* Letter spacing examples */
h1 {
letter-spacing: 1px; /* Adds 1px between each character */
}
.tight-text {
letter-spacing: -0.5px; /* Reduces space between characters */
}
.spaced-text {
letter-spacing: 0.2em; /* Relative to font size */
}
Use cases: Adjusting headings for better appearance, creating special text effects, improving readability of all-caps text
word-spacing
The word-spacing property adjusts the space between words.
/* Word spacing examples */
p {
word-spacing: 0.05em; /* Slight increase in word spacing */
}
.wide-spacing {
word-spacing: 0.3em; /* Significant increase in word spacing */
}
.tight-spacing {
word-spacing: -0.1em; /* Reduced word spacing */
}
Use cases: Improving readability of justified text, stylistic effects for headings or quotes
Line and Paragraph Properties
These properties control how text is arranged and spaced in paragraphs and blocks.
line-height
The line-height property sets the height of each line of text.
/* Line height examples */
body {
line-height: 1.5; /* 1.5 times the font size (unitless) */
}
p {
line-height: 1.6; /* Good for body text */
}
h1, h2, h3 {
line-height: 1.2; /* Tighter for headings */
}
.code-block {
line-height: 1.8; /* More space for code */
}
Best practice: Use unitless values for line-height (e.g., 1.5 instead of 1.5em or 150%). This ensures that descendant elements calculate their line heights based on their own font sizes, not the parent's.
Readability: For most body text, a line-height between 1.4 and 1.6 is considered optimal for readability.
text-justify
The text-justify property defines how justified text should be aligned.
/* Text justify examples - use with text-align: justify */
.justified-text {
text-align: justify;
text-justify: inter-word; /* Adjusts space between words (default) */
}
.newspaper-style {
text-align: justify;
text-justify: inter-character; /* Adjusts space between characters too */
}
Browser support: Limited support; test thoroughly if using this property.
hyphens
The hyphens property controls how words break at line ends with hyphens.
/* Hyphenation examples */
.auto-hyphenate {
hyphens: auto; /* Browser decides when to hyphenate */
/* lang attribute must be set on the element or a parent for this to work properly */
}
.manual-hyphenate {
hyphens: manual; /* Only at (soft hyphen) or explicit hyphens */
}
.no-hyphenate {
hyphens: none; /* No hyphenation */
}
Language dependency: Automatic hyphenation requires the lang attribute to be set on HTML elements (e.g., <html lang="en">).
text-align-last
The text-align-last property defines how the last line of a paragraph is aligned.
/* Text align last examples */
.justify-paragraph {
text-align: justify;
text-align-last: right; /* Last line is right-aligned */
}
.center-last {
text-align-last: center; /* Centers the last line */
}
Use case: Creating special effects with paragraph endings, controlling the appearance of justified text
line-break
The line-break property defines how line breaks in Asian languages are handled.
/* Line break examples */
.asian-text {
line-break: strict; /* More line breaking rules for CJK text */
}
.normal-break {
line-break: normal; /* Standard line breaking rules */
}
Use case: Primarily for Chinese, Japanese, and Korean text layout
hanging-punctuation
The hanging-punctuation property allows punctuation marks to be placed outside the text box.
/* Hanging punctuation example */
.quote {
hanging-punctuation: first; /* Opening quote hangs outside the text box */
}
Use case: Creating more visually balanced paragraphs, especially with quoted text
Browser support: Limited; check compatibility before using
Web Fonts and Custom Typography
Web fonts allow you to use typefaces beyond the standard system fonts, greatly expanding your typographic options.
Web Font Services
Services like Google Fonts provide free, easy-to-use web fonts:
/* Google Fonts implementation */
/* Step 1: Add link to the font in the HTML head */
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap" rel="stylesheet">
/* Step 2: Use the font in your CSS */
body {
font-family: 'Roboto', sans-serif;
}
Popular services:
- Google Fonts (free)
- Adobe Fonts (subscription)
- Fonts.com (paid)
- Typography.com (paid)
@font-face
The @font-face rule allows you to use custom fonts hosted on your server.
/* @font-face rule example */
@font-face {
font-family: 'MyCustomFont';
src: url('/fonts/custom-font.woff2') format('woff2'),
url('/fonts/custom-font.woff') format('woff');
font-weight: normal;
font-style: normal;
font-display: swap; /* Controls how the font is displayed while loading */
}
/* Using the custom font */
h1 {
font-family: 'MyCustomFont', sans-serif;
}
Font formats:
- WOFF2: Web Open Font Format 2 - Best compression and performance, wide modern browser support
- WOFF: Web Open Font Format - Good compression, fallback for older browsers
- TTF/OTF: TrueType/OpenType - Less efficient, but supported by most browsers
- EOT: Embedded OpenType - Only for Internet Explorer (legacy)
font-display Property
The font-display property controls how a font is displayed while it's being loaded.
@font-face {
font-family: 'MyCustomFont';
src: url('/fonts/custom-font.woff2') format('woff2');
font-display: swap; /* Shows a fallback font until the custom font loads */
}
font-display values:
- auto: Browser's default behavior
- block: Briefly hide text until the font loads (short block period, then fallback, then swap)
- swap: Use a fallback font until the custom font loads (no block period)
- fallback: Brief block period, then fallback font, then custom font only if it loads quickly
- optional: Brief block period, then fallback font, may or may not load custom font based on connection
Best practice: Use swap for critical content and fallback or optional for decorative fonts.
Variable Fonts
Variable fonts are a newer font technology that combines multiple font weights, widths, and styles into a single file.
/* Variable font implementation */
@font-face {
font-family: 'MyVariableFont';
src: url('/fonts/variable-font.woff2') format('woff2-variations');
font-weight: 100 900; /* Weight range */
font-stretch: 75% 125%; /* Width range */
font-style: oblique 0deg 12deg; /* Style range */
}
/* Using variable font properties */
.heading {
font-family: 'MyVariableFont', sans-serif;
font-weight: 650; /* Any value between 100-900 */
font-stretch: 110%; /* Any value between 75%-125% */
font-style: oblique 8deg; /* Any value between 0-12 degrees */
}
Advantages: Smaller file sizes, more design flexibility, smoother animations between styles
Browser support: Good in modern browsers, but check compatibility
Font Loading Performance
Web fonts can impact performance, especially on slower connections. Consider these best practices:
- Limit font weights and styles: Only load what you need
- Subset fonts: Only include the character sets you need (e.g., Latin only)
- Preload critical fonts: Use the
<link rel="preload">tag for key fonts - Use font-display: Control the loading behavior
- Consider variable fonts: They can be more efficient when you need multiple weights
/* Preloading a critical font */
<link rel="preload" href="/fonts/critical-font.woff2" as="font" type="font/woff2" crossorigin>
Responsive Typography
Responsive typography adapts to different screen sizes and devices for optimal readability.
Relative Units
Using relative units allows text to scale proportionally across devices.
/* Responsive typography with relative units */
html {
font-size: 16px; /* Base font size */
}
@media (max-width: 768px) {
html {
font-size: 14px; /* Smaller base font size on smaller screens */
}
}
h1 {
font-size: 2.5rem; /* 2.5 × root font size */
}
p {
font-size: 1rem; /* 1 × root font size */
}
Viewport Units
Viewport units can create text that scales with the viewport size.
/* Responsive typography with viewport units */
h1 {
font-size: 5vw; /* 5% of viewport width */
}
/* Combining units for controlled scaling */
h2 {
font-size: calc(1.5rem + 1vw); /* Minimum size plus viewport scaling */
}
Caution: Pure viewport units can make text too small on mobile or too large on desktop. The calc() approach provides more control.
fluid-typography with clamp()
The clamp() function sets a minimum, preferred, and maximum size.
/* Fluid typography with clamp() */
h1 {
font-size: clamp(2rem, 5vw, 4rem);
/* Minimum: 2rem, Preferred: 5vw, Maximum: 4rem */
}
p {
font-size: clamp(1rem, 1rem + 0.5vw, 1.5rem);
/* Scales smoothly between 1rem and 1.5rem */
}
Benefit: Combines the advantages of both relative and viewport units while preventing extremes.
Responsive Line Length
Controlling line length (characters per line) is crucial for readability.
/* Responsive line length control */
p {
max-width: 65ch; /* Limits width to approximately 65 characters */
margin-left: auto;
margin-right: auto;
}
@media (max-width: 600px) {
p {
max-width: 100%; /* Full width on small screens */
}
}
Best practice: Optimal line length for reading is generally 45-75 characters. The ch unit represents the width of the "0" character in the current font.
Media Queries for Typography
Adjust typography for different screen sizes using media queries.
/* Typography adjustments with media queries */
h1 {
font-size: 3rem;
line-height: 1.2;
}
@media (max-width: 768px) {
h1 {
font-size: 2.5rem;
line-height: 1.3; /* Slightly increased for better readability */
}
}
@media (max-width: 480px) {
h1 {
font-size: 2rem;
line-height: 1.4;
}
}
Beyond font size: Consider adjusting other properties like line-height, letter-spacing, and paragraph spacing for different screen sizes.
Typography Best Practices
Follow these guidelines for effective web typography.
Readability Fundamentals
- Adequate font size: Minimum 16px for body text
- Appropriate line height: Generally 1.4-1.6 for body text
- Reasonable line length: 45-75 characters per line
- Sufficient contrast: WCAG recommends at least 4.5:1 contrast ratio for normal text
- Clear type scale: Establish a consistent hierarchy of sizes
Type Scale
A type scale is a set of predefined font sizes that create a harmonious hierarchy.
/* Sample type scale using a 1.25 ratio (Major Third) */
:root {
--scale-ratio: 1.25;
--text-xs: 0.8rem;
--text-sm: 1rem;
--text-md: calc(var(--text-sm) * var(--scale-ratio)); /* 1.25rem */
--text-lg: calc(var(--text-md) * var(--scale-ratio)); /* 1.563rem */
--text-xl: calc(var(--text-lg) * var(--scale-ratio)); /* 1.953rem */
--text-2xl: calc(var(--text-xl) * var(--scale-ratio)); /* 2.441rem */
--text-3xl: calc(var(--text-2xl) * var(--scale-ratio)); /* 3.052rem */
}
body { font-size: var(--text-sm); }
h3 { font-size: var(--text-lg); }
h2 { font-size: var(--text-xl); }
h1 { font-size: var(--text-2xl); }
.display { font-size: var(--text-3xl); }
.small { font-size: var(--text-xs); }
Common ratios:
- 1.067 (Minor Second): Subtle scale with minimal contrast
- 1.125 (Major Second): Conservative, safe scale
- 1.2 (Minor Third): Moderate contrast
- 1.25 (Major Third): Balanced contrast
- 1.333 (Perfect Fourth): Traditional typography scale
- 1.5 (Perfect Fifth): Strong, dramatic scale
Font Pairing
Combining fonts effectively creates visual interest while maintaining harmony.
/* Font pairing example */
h1, h2, h3, h4, h5, h6 {
font-family: 'Playfair Display', serif; /* Elegant serif for headings */
font-weight: 700;
}
body {
font-family: 'Source Sans Pro', sans-serif; /* Clean sans-serif for body */
font-weight: 400;
}
Font pairing guidelines:
- Create contrast: Pair serif with sans-serif, or a bold display face with a neutral body font
- Maintain harmony: Choose fonts with similar x-heights or similar character shapes
- Limit the number: Generally, use no more than 2-3 font families per design
- Establish clear roles: Assign specific fonts to specific functions (headings, body, UI, etc.)
Vertical Rhythm
Vertical rhythm creates a consistent spacing pattern down the page.
/* Establishing vertical rhythm */
:root {
--baseline: 1.5rem; /* Base rhythm unit */
}
p {
margin-top: 0;
margin-bottom: var(--baseline);
line-height: var(--baseline);
}
h1 {
font-size: 2.5rem;
line-height: calc(var(--baseline) * 2); /* 3rem */
margin-top: calc(var(--baseline) * 2); /* 3rem */
margin-bottom: var(--baseline); /* 1.5rem */
}
h2 {
font-size: 2rem;
line-height: calc(var(--baseline) * 1.5); /* 2.25rem */
margin-top: calc(var(--baseline) * 1.5); /* 2.25rem */
margin-bottom: var(--baseline); /* 1.5rem */
}
Key concept: All vertical spacing values (margins, paddings, line heights) are multiples of a single base value.
Accessibility Considerations
Ensure your typography is accessible to all users:
- Color contrast: Meet WCAG guidelines (4.5:1 for normal text, 3:1 for large text)
- Text resizing: Ensure text can be resized up to 200% without breaking the layout
- Line height: WCAG 2.1 recommends line height of at least 1.5 for paragraph text
- Letter and word spacing: Maintain adequate spacing for readability
- Font choice: Select fonts with clear character shapes
- Alternative text: Provide text alternatives for stylized text in images
/* Accessibility-friendly typography */
body {
font-size: 1rem; /* Min 16px */
line-height: 1.5; /* WCAG 2.1 recommendation */
letter-spacing: 0.01em; /* Slight improvement for readability */
word-spacing: 0.05em; /* Slight improvement for readability */
color: #333; /* Ensure good contrast with background */
}
Common Typography Patterns
Let's explore some practical typography patterns and techniques.
Article Typography
/* Article typography styles */
.article {
font-family: 'Georgia', serif;
font-size: 1.125rem;
line-height: 1.6;
max-width: 65ch;
margin: 0 auto;
}
.article h1 {
font-size: 2.5rem;
line-height: 1.2;
margin-bottom: 1.5rem;
}
.article h2 {
font-size: 1.8rem;
line-height: 1.3;
margin-top: 2.5rem;
margin-bottom: 1rem;
}
.article p + p {
margin-top: 1.5rem;
}
.article blockquote {
font-style: italic;
border-left: 4px solid #ddd;
padding-left: 1.5rem;
margin-left: 0;
color: #555;
}
.article figcaption {
font-size: 0.9rem;
color: #666;
margin-top: 0.5rem;
text-align: center;
}
Pull Quotes
/* Pull quote styles */
.pull-quote {
font-family: 'Georgia', serif;
font-size: 1.5rem;
line-height: 1.4;
font-style: italic;
position: relative;
padding: 1.5rem 0;
margin: 2rem 0;
border-top: 2px solid #ddd;
border-bottom: 2px solid #ddd;
text-align: center;
}
.pull-quote::before {
content: '"';
font-size: 4rem;
line-height: 1;
color: #ddd;
position: absolute;
top: -1rem;
left: -0.5rem;
}
Drop Caps
/* Drop cap effect */
.drop-cap::first-letter {
float: left;
font-size: 4rem;
line-height: 0.8;
font-weight: bold;
margin-right: 0.1em;
color: #333;
}
Small Caps for Headings
/* Small caps heading */
.small-caps-heading {
font-size: 1.5rem;
text-transform: uppercase;
letter-spacing: 0.1em;
font-weight: 400; /* Often lighter weight works better with uppercase */
}
/* True small caps when available */
.true-small-caps {
font-variant: small-caps;
font-feature-settings: "smcp"; /* OpenType feature for true small caps */
}
Gradient Text
/* Gradient text effect */
.gradient-text {
background: linear-gradient(45deg, #ff6b6b, #5e60ce);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
/* Enhance visibility for older browsers that don't support gradient text */
position: relative;
z-index: 1;
}
Browser support: The background-clip: text property needs vendor prefixes for older browsers.
Text with Icon Alignment
/* Text with icon alignment */
.icon-text {
display: flex;
align-items: center;
gap: 0.5rem;
}
.icon-text svg,
.icon-text img {
width: 1.2em;
height: 1.2em;
}
Multi-Column Text
/* Multi-column text layout */
.multi-column {
column-count: 2;
column-gap: 2rem;
column-rule: 1px solid #ddd;
}
@media (max-width: 768px) {
.multi-column {
column-count: 1; /* Revert to single column on smaller screens */
}
}
/* Ensure headings don't get split between columns */
.multi-column h2,
.multi-column h3 {
column-span: all; /* Makes headings span across all columns */
margin-top: 1.5rem;
margin-bottom: 1rem;
}
Hands-On Exercise: Typography Systems
Let's create a complete typography system that can be applied to any website.
Exercise Overview
In this exercise, we'll build a typography system with different components.
HTML Structure
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Typography System</title>
<link rel="stylesheet" href="/styles/typography.css">
<link href="https://fonts.googleapis.com/css2?family=Playfair+Display:ital,wght@0,400;0,700;1,400&family=Source+Sans+Pro:ital,wght@0,300;0,400;0,600;0,700;1,400&display=swap" rel="stylesheet">
</head>
<body>
<div class="container">
<header class="header">
<h1>Typography System</h1>
<p class="subtitle">A complete set of typographic styles for web projects</p>
</header>
<section class="section">
<h2>Type Scale</h2>
<div class="type-scale">
<div class="scale-item">
<span class="text-xs">Extra Small Text (--text-xs)</span>
<code>0.75rem</code>
</div>
<div class="scale-item">
<span class="text-sm">Small Text (--text-sm)</span>
<code>0.875rem</code>
</div>
<div class="scale-item">
<span class="text-base">Base Text (--text-base)</span>
<code>1rem</code>
</div>
<div class="scale-item">
<span class="text-lg">Large Text (--text-lg)</span>
<code>1.25rem</code>
</div>
<div class="scale-item">
<span class="text-xl">Extra Large Text (--text-xl)</span>
<code>1.5rem</code>
</div>
<div class="scale-item">
<span class="text-2xl">2XL Text (--text-2xl)</span>
<code>2rem</code>
</div>
<div class="scale-item">
<span class="text-3xl">3XL Text (--text-3xl)</span>
<code>2.5rem</code>
</div>
<div class="scale-item">
<span class="text-4xl">4XL Text (--text-4xl)</span>
<code>3rem</code>
</div>
</div>
</section>
<section class="section">
<h2>Headings</h2>
<div class="heading-examples">
<h1>Heading Level 1</h1>
<h2>Heading Level 2</h2>
<h3>Heading Level 3</h3>
<h4>Heading Level 4</h4>
<h5>Heading Level 5</h5>
<h6>Heading Level 6</h6>
</div>
</section>
<section class="section">
<h2>Body Text</h2>
<div class="body-examples">
<p>This is a standard paragraph with the base font size. Good typography is important for readability and user experience. The right balance of font size, line height, and line length can make text much easier to read.</p>
<p>When creating a typography system, consider the needs of your users. Is the text primarily for reading long-form content? Or is it for quick scanning of information? Different purposes may require different typographic treatments.</p>
<p class="lead">This is a lead paragraph, often used at the beginning of an article to introduce the content. It's typically larger or visually distinct from regular paragraphs.</p>
<p class="small">This is smaller text, often used for supplementary information, captions, footnotes, or legal text that doesn't need to be emphasized.</p>
</div>
</section>
<section class="section">
<h2>Text Variations</h2>
<div class="text-variations">
<p><strong>This text is bold or strong</strong>, which adds emphasis and visual weight.</p>
<p><em>This text is emphasized or italic</em>, which adds a different kind of emphasis and is often used for titles, foreign words, or to stress certain words.</p>
<p><u>This text is underlined</u>, though underlines are generally avoided except for links.</p>
<p><mark>This text is highlighted</mark>, which can be useful for emphasizing important information or search terms.</p>
<p><del>This text is deleted</del> <ins>and this text is inserted</ins>, which can be used to show changes in content.</p>
<p><code>This is inline code</code>, often used for programming terms or commands.</p>
<p><kbd>This is keyboard input</kbd>, used to represent key commands or user input.</p>
<p class="uppercase">This text is uppercase, which can be used for headings or emphasis.</p>
<p class="capitalize">this text is capitalized, with the first letter of each word in uppercase.</p>
<p class="small-caps">This text uses small caps, where lowercase letters are converted to smaller uppercase letters.</p>
</div>
</section>
<section class="section">
<h2>Links and Buttons</h2>
<div class="link-examples">
<p>This is a paragraph with a <a href="#">standard link</a> embedded within it.</p>
<p>
<a href="#" class="button button-primary">Primary Button</a>
<a href="#" class="button button-secondary">Secondary Button</a>
</p>
</div>
</section>
<section class="section">
<h2>Lists</h2>
<div class="list-examples">
<h3>Unordered List</h3>
<ul>
<li>This is the first list item</li>
<li>This is the second list item
<ul>
<li>This is a nested list item</li>
<li>This is another nested list item</li>
</ul>
</li>
<li>This is the third list item</li>
</ul>
<h3>Ordered List</h3>
<ol>
<li>This is the first list item</li>
<li>This is the second list item
<ol>
<li>This is a nested list item</li>
<li>This is another nested list item</li>
</ol>
</li>
<li>This is the third list item</li>
</ol>
</div>
</section>
<section class="section">
<h2>Blockquotes</h2>
<div class="blockquote-examples">
<blockquote>
<p>Good typography is invisible. Bad typography is everywhere.</p>
<cite>— Attributed to various designers</cite>
</blockquote>
<div class="pull-quote">
<p>Typography is what language looks like.</p>
<cite>— Ellen Lupton</cite>
</div>
</div>
</section>
<section class="section">
<h2>Code Blocks</h2>
<div class="code-examples">
<pre><code>/* CSS Code Example */
body {
font-family: 'Source Sans Pro', sans-serif;
line-height: 1.5;
color: #333;
}
h1, h2, h3, h4, h5, h6 {
font-family: 'Playfair Display', serif;
margin-top: 1.5em;
margin-bottom: 0.5em;
}</code></pre>
</div>
</section>
</div>
</body>
</html>
CSS Implementation
/* Typography System CSS */
/* Base Variables */
:root {
/* Typography Scale (1.25 Major Third ratio) */
--text-xs: 0.75rem;
--text-sm: 0.875rem;
--text-base: 1rem;
--text-lg: 1.25rem;
--text-xl: 1.5rem;
--text-2xl: 2rem;
--text-3xl: 2.5rem;
--text-4xl: 3rem;
/* Font Families */
--font-display: 'Playfair Display', Georgia, serif;
--font-body: 'Source Sans Pro', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Arial, sans-serif;
--font-mono: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
/* Font Weights */
--font-weight-light: 300;
--font-weight-normal: 400;
--font-weight-medium: 500;
--font-weight-semibold: 600;
--font-weight-bold: 700;
/* Line Heights */
--line-height-none: 1;
--line-height-tight: 1.25;
--line-height-snug: 1.375;
--line-height-normal: 1.5;
--line-height-relaxed: 1.625;
--line-height-loose: 2;
/* Letter Spacing */
--letter-spacing-tighter: -0.05em;
--letter-spacing-tight: -0.025em;
--letter-spacing-normal: 0;
--letter-spacing-wide: 0.025em;
--letter-spacing-wider: 0.05em;
--letter-spacing-widest: 0.1em;
/* Color Palette */
--color-text: #333333;
--color-text-light: #666666;
--color-text-lighter: #999999;
--color-link: #0066cc;
--color-link-hover: #004d99;
--color-primary: #0066cc;
--color-secondary: #6c757d;
--color-highlight: #fff3bf;
/* Base Spacing */
--spacing-base: 1rem;
}
/* Base Styles */
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html {
font-size: 16px;
}
body {
font-family: var(--font-body);
font-weight: var(--font-weight-normal);
font-size: var(--text-base);
line-height: var(--line-height-normal);
color: var(--color-text);
background-color: #ffffff;
}
/* Container */
.container {
max-width: 800px;
margin: 0 auto;
padding: calc(var(--spacing-base) * 2);
}
/* Sections */
.section {
margin-bottom: calc(var(--spacing-base) * 4);
}
.header {
margin-bottom: calc(var(--spacing-base) * 4);
text-align: center;
}
/* Type Scale Classes */
.text-xs { font-size: var(--text-xs); }
.text-sm { font-size: var(--text-sm); }
.text-base { font-size: var(--text-base); }
.text-lg { font-size: var(--text-lg); }
.text-xl { font-size: var(--text-xl); }
.text-2xl { font-size: var(--text-2xl); }
.text-3xl { font-size: var(--text-3xl); }
.text-4xl { font-size: var(--text-4xl); }
/* Type Scale Display */
.type-scale {
display: flex;
flex-direction: column;
gap: var(--spacing-base);
}
.scale-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: calc(var(--spacing-base) * 0.5);
background-color: #f8f9fa;
border-radius: 4px;
}
.scale-item code {
color: var(--color-text-light);
font-family: var(--font-mono);
font-size: var(--text-sm);
}
/* Headings */
h1, h2, h3, h4, h5, h6 {
font-family: var(--font-display);
font-weight: var(--font-weight-bold);
line-height: var(--line-height-tight);
color: var(--color-text);
margin-bottom: var(--spacing-base);
}
h1 {
font-size: var(--text-4xl);
line-height: var(--line-height-none);
margin-bottom: calc(var(--spacing-base) * 1.5);
}
h2 {
font-size: var(--text-3xl);
margin-top: calc(var(--spacing-base) * 2);
margin-bottom: calc(var(--spacing-base) * 1.5);
position: relative;
padding-bottom: calc(var(--spacing-base) * 0.5);
}
h2::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
width: 50px;
height: 3px;
background-color: var(--color-primary);
}
h3 {
font-size: var(--text-2xl);
margin-top: calc(var(--spacing-base) * 1.5);
margin-bottom: var(--spacing-base);
}
h4 {
font-size: var(--text-xl);
margin-top: calc(var(--spacing-base) * 1.5);
}
h5 {
font-size: var(--text-lg);
margin-top: var(--spacing-base);
}
h6 {
font-size: var(--text-base);
font-weight: var(--font-weight-semibold);
margin-top: var(--spacing-base);
}
.subtitle {
font-size: var(--text-xl);
color: var(--color-text-light);
font-weight: var(--font-weight-normal);
margin-top: calc(var(--spacing-base) * 0.5);
}
/* Paragraphs and Body Text */
p {
margin-bottom: var(--spacing-base);
}
.lead {
font-size: var(--text-xl);
line-height: var(--line-height-snug);
color: var(--color-text-light);
margin-bottom: calc(var(--spacing-base) * 1.5);
}
.small {
font-size: var(--text-sm);
color: var(--color-text-lighter);
}
/* Text Variations */
strong, b {
font-weight: var(--font-weight-bold);
}
em, i {
font-style: italic;
}
mark {
background-color: var(--color-highlight);
padding: 0.1em 0.2em;
border-radius: 0.2em;
}
code {
font-family: var(--font-mono);
background-color: #f0f0f0;
padding: 0.1em 0.3em;
border-radius: 0.2em;
font-size: 0.9em;
}
kbd {
font-family: var(--font-mono);
background-color: #f0f0f0;
padding: 0.1em 0.3em;
border-radius: 0.2em;
border: 1px solid #ccc;
box-shadow: 0 1px 0 rgba(0,0,0,0.2);
font-size: 0.9em;
}
.uppercase {
text-transform: uppercase;
letter-spacing: var(--letter-spacing-wide);
}
.capitalize {
text-transform: capitalize;
}
.small-caps {
font-variant: small-caps;
letter-spacing: var(--letter-spacing-wide);
}
/* Links and Buttons */
a {
color: var(--color-link);
text-decoration: underline;
text-underline-offset: 0.2em;
transition: color 0.2s;
}
a:hover, a:focus {
color: var(--color-link-hover);
}
.button {
display: inline-block;
font-family: var(--font-body);
font-size: var(--text-base);
font-weight: var(--font-weight-medium);
text-decoration: none;
padding: 0.75em 1.5em;
border-radius: 4px;
cursor: pointer;
transition: all 0.2s;
}
.button-primary {
background-color: var(--color-primary);
color: white;
}
.button-primary:hover, .button-primary:focus {
background-color: var(--color-link-hover);
color: white;
}
.button-secondary {
background-color: var(--color-secondary);
color: white;
}
.button-secondary:hover, .button-secondary:focus {
background-color: #5a6268;
color: white;
}
/* Lists */
ul, ol {
margin-bottom: var(--spacing-base);
padding-left: 2em;
}
li {
margin-bottom: calc(var(--spacing-base) * 0.3);
}
li ul, li ol {
margin-top: calc(var(--spacing-base) * 0.3);
margin-bottom: 0;
}
/* Blockquotes */
blockquote {
font-family: var(--font-display);
font-style: italic;
margin: calc(var(--spacing-base) * 1.5) 0;
padding: var(--spacing-base) calc(var(--spacing-base) * 2);
border-left: 4px solid var(--color-primary);
background-color: #f8f9fa;
}
blockquote p {
margin-bottom: calc(var(--spacing-base) * 0.5);
}
blockquote cite {
font-family: var(--font-body);
font-style: normal;
font-size: var(--text-sm);
color: var(--color-text-light);
display: block;
text-align: right;
}
.pull-quote {
font-family: var(--font-display);
font-size: var(--text-2xl);
line-height: var(--line-height-tight);
font-style: italic;
max-width: 80%;
margin: calc(var(--spacing-base) * 2) auto;
text-align: center;
color: var(--color-text);
position: relative;
}
.pull-quote::before {
content: '"';
font-size: 4em;
position: absolute;
left: -0.5em;
top: -0.5em;
color: rgba(0, 0, 0, 0.1);
}
.pull-quote cite {
font-family: var(--font-body);
font-style: normal;
font-size: var(--text-sm);
color: var(--color-text-light);
display: block;
margin-top: var(--spacing-base);
}
/* Code Blocks */
pre {
background-color: #f0f0f0;
padding: var(--spacing-base);
border-radius: 4px;
margin-bottom: var(--spacing-base);
overflow-x: auto;
}
pre code {
background-color: transparent;
padding: 0;
font-size: var(--text-sm);
white-space: pre;
}
/* Media Queries for Responsive Typography */
@media (max-width: 768px) {
:root {
--text-4xl: 2.5rem;
--text-3xl: 2rem;
--text-2xl: 1.75rem;
--text-xl: 1.25rem;
}
.container {
padding: var(--spacing-base);
}
.pull-quote {
font-size: var(--text-xl);
max-width: 100%;
}
}
@media (max-width: 480px) {
html {
font-size: 15px; /* Slightly reduced base size for very small screens */
}
:root {
--text-4xl: 2rem;
--text-3xl: 1.75rem;
--text-2xl: 1.5rem;
}
h1 {
line-height: var(--line-height-tight);
}
.scale-item {
flex-direction: column;
align-items: flex-start;
gap: 0.5rem;
}
}
Exercise Analysis
This exercise demonstrates several important typography concepts:
- CSS variables for typography: Creating a consistent, maintainable type system
- Type scale: Establishing a harmonious progression of font sizes
- Font pairing: Combining a serif display font with a sans-serif body font
- Vertical rhythm: Consistent spacing between elements
- Text variations: Different styles for different purposes
- Responsive adjustments: Adapting typography for different screen sizes
- Semantic HTML: Using appropriate elements for different text roles
The exercise creates a comprehensive typography system that could be used as a foundation for any website or application.
Further Resources and Next Steps
Typography Tools and References
- Type Scale - Visual calculator for font sizing
- Modular Scale - Advanced type scale calculator
- Google Fonts - Free web fonts
- FontPair - Font pairing suggestions
- WebAIM Contrast Checker - Verify text accessibility
- Font Face Observer - JavaScript library for font loading
Typography Articles and Guides
- 10 Principles for Typography Usage in UI Design
- Better Web Typography - Free course on web typography
- Web Typography: Best Practices and Examples
- Typewolf - Typography inspiration and resources
Advanced Topics to Explore
- Variable Fonts: Single font files with multiple variations
- OpenType Features: Advanced typographic capabilities using
font-feature-settings - Internationalization: Typography considerations for different languages
- Fluid Typography: Advanced responsive text sizing techniques
- Typographic Animation: Adding motion to text elements
- Typography for Interactive Elements: Special considerations for buttons, forms, etc.
Today's Assignment: Create a Typography Style Guide
Now it's your turn to apply what you've learned about typography.
Assignment Requirements:
- Create a new file called
styles/typography_guide.css - Create a corresponding HTML file called
typography_guide.html - Design a complete typography style guide that includes:
- A consistent type scale with at least 5 sizes
- Appropriate font selections (you can use Google Fonts or system fonts)
- Heading styles (h1-h6)
- Paragraph styles (regular, lead, small)
- Text variations (bold, italic, links, etc.)
- Block elements (blockquotes, lists, code blocks)
- Button text styles
- Use CSS variables for all typography-related values
- Implement responsive adjustments for at least two breakpoints
- Include comments in your CSS explaining your typography choices
- Create a page that showcases all text elements with appropriate examples
Bonus challenges:
- Implement a custom drop cap effect
- Create a pull quote style
- Add a dark mode version of your typography
- Implement special text effects (gradient text, text shadows, etc.)
- Add multi-column text layout for larger screens
- Create utility classes for common text modifications
Submit your completed assignment by pushing both your HTML and CSS files to your course repository.
Wrapping Up
Congratulations! You've now explored the fundamental principles and techniques of typography on the web. Typography is both an art and a science - it requires technical knowledge of CSS properties as well as an aesthetic understanding of what makes text readable and visually appealing.
Key takeaways from today's session:
- Typography is a critical component of user experience and brand identity
- CSS offers extensive control over text appearance and behavior
- Establishing a type scale creates visual harmony and hierarchy
- Font selection should consider both aesthetics and practicality
- Responsive typography ensures readability across all devices
- Consistency is key for professional typography
- Accessibility should always be a consideration in typographic choices
As you continue your CSS journey, you'll find that typography skills are fundamental to creating professional-looking websites and applications. The concepts you've learned today will help you communicate more effectively with your users through text.
In our next session, we'll explore CSS positioning, which will give you precise control over the placement of elements on your page.
Any questions before we wrap up?