Course Lessons

CSS Styling

Back to Course

Typography & Units

CSS Styling Lesson 3 of 10 16 min

Webbo3 Data Analysis Bootcamp · CSS Module · Lesson 1

Typography and Units: Controlling Text Appearance with CSS Properties, Measurement Systems, and Font Imports

A foundational lesson covering every CSS property that controls text appearance, the differences between absolute and relative units, how to import custom fonts from Google Fonts, and text alignment and transformation techniques.

Typography and text design

Text is the primary medium of the web. Every headline, paragraph, button label, and data point you display starts as text. How that text looks, its size, its weight, its spacing, its alignment, determines whether your dashboard is readable at a glance or exhausting to parse. CSS gives you precise control over every aspect of typography, but that control is only useful if you understand the tools correctly. Using pixels when you should use rems, or setting line-height as a percentage when you need a unitless number, creates subtle bugs that compound across a large project. This lesson teaches you the properties, the units, the font systems, and the alignment techniques you need to build text that looks professional on every screen size. These are not decorative details. They are the difference between a dashboard that communicates and one that confuses.

1. font-family: Choosing Typefaces

The font-family property specifies which typeface should render your text. Because not every computer has the same fonts installed, you provide a list of fallbacks separated by commas. The browser tries each font in order until it finds one that is available.

Basic syntax with fallbacks.

body {
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}

The browser first tries Segoe UI. If that is not installed, it tries Tahoma. Then Geneva. Then Verdana. The final fallback, sans-serif, is a generic family name that tells the browser to use any sans-serif font available on the system. Generic families include serif, sans-serif, monospace, cursive, and fantasy. Always end your font stack with a generic family. Without it, if none of your named fonts are available, the browser falls back to its default, which might be a serif font when you wanted sans-serif.

Font names with spaces need quotes. If a font name contains spaces, like Times New Roman or Segoe UI, you must wrap it in single or double quotes. Single-word names like Arial or Georgia do not need quotes, though adding them does no harm.

Practical font stacks for dashboards. For data-heavy dashboards, readability is paramount. Sans-serif fonts are generally preferred for screens because their clean lines render well at small sizes. A solid dashboard font stack is:

body {
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
}

This stack gives native-looking fonts on every major platform: San Francisco on Apple devices, Segoe UI on Windows, Roboto on Android, and Ubuntu on Linux systems. It is the system font stack used by GitHub, Medium, and Bootstrap, because it feels native to the user's device while maintaining consistency.

2. font-size: Controlling Text Size

The font-size property sets the height of the text. The unit you choose matters more than the number itself, because different units behave differently when the user changes their browser settings or views your page on a different device.

Pixels (px): absolute and fixed. Pixels are the most intuitive unit. font-size: 16px means the text is exactly sixteen pixels tall on the screen. Pixels are precise and predictable, which is why beginners prefer them. The drawback is that pixels are absolute. If a user with poor vision increases their browser's default font size, text defined in pixels does not scale. It stays at 16px regardless of user preference. This is an accessibility failure. For body text, avoid pixels. Reserve them for borders, shadows, and other elements that should not scale.

Rems (rem): relative to the root. One rem equals the font-size of the root element, which is the html tag. By default, browsers set html font-size to 16px, so 1rem equals 16px, 1.5rem equals 24px, and 0.875rem equals 14px. The critical difference from pixels is that if the user changes their browser's default font size to 20px, 1rem becomes 20px automatically. Your entire layout scales proportionally without you changing a single line of CSS. This is why rems are the modern standard for font sizing. Set your root size in pixels if you want a predictable base, then use rems everywhere else:

html {
  font-size: 16px;
}

h1 {
  font-size: 2rem;  /* 32px */
}

p {
  font-size: 1rem;  /* 16px */
}

small {
  font-size: 0.875rem;  /* 14px */
}

Ems (em): relative to the parent. One em equals the font-size of the current element's parent. If a div has font-size: 20px, then any child element with font-size: 1.5em will be 30px. The problem with ems is compounding. If you nest elements with em-based sizes, each child multiplies against its parent, and the result can balloon unexpectedly:

.parent { font-size: 1.2em; }  /* 19.2px if root is 16px */
.child { font-size: 1.2em; }   /* 23.04px, compounding */
.grandchild { font-size: 1.2em; }  /* 27.65px, compounding again */

Because of this compounding behavior, ems are best reserved for properties where you want the value to scale with the element's own font-size, like padding or margin on a button. For font-size itself, rems are safer and more predictable.

Percentages (%): relative to the parent font-size. When applied to font-size, percentages behave exactly like ems. font-size: 100% means the same as the parent's font-size. font-size: 150% means one and a half times the parent's size. Percentages are rarely used for font-size in modern CSS because rems are clearer, but you will still see them in legacy codebases.

Viewport units (vw and vh): relative to the screen. One vw equals one percent of the viewport width. One vh equals one percent of the viewport height. font-size: 5vw means the text will be five percent of the screen width, so on a 1200px wide screen it renders at 60px, and on a 400px wide phone it renders at 20px. Viewport units are useful for massive display headlines that need to scale dramatically across devices, but they are dangerous for body text because they can become unreadably small on narrow screens or absurdly large on wide monitors. If you use vw for font-size, always combine it with a minimum and maximum using clamp:

h1 {
  font-size: clamp(1.5rem, 4vw, 3rem);
}

This sets a minimum of 1.5rem, a preferred size of 4vw, and a maximum of 3rem. The text scales smoothly between the minimum and maximum, never going below 1.5rem or above 3rem regardless of screen width. This is the modern approach to responsive typography.

Code editor and web development

3. font-weight: Controlling Boldness

The font-weight property controls how thick or thin the text appears. It accepts numeric values from 100 to 900 in increments of 100, or keyword values like normal and bold.

Numeric values and their meanings. 100 is ultra-thin. 400 is normal, the default for most text. 700 is bold. 900 is black or heavy. Not every font supports every weight. If you specify font-weight: 200 on a font that only comes in 400 and 700, the browser will round to the nearest available weight, usually 400. To use numeric weights effectively, you must import the specific font weights you need.

Keyword values. normal is equivalent to 400. bold is equivalent to 700. lighter makes the text one weight lighter than its parent. bolder makes it one weight heavier than its parent. These relative keywords are rarely used because their behavior depends on the parent's weight, which can be unpredictable.

Practical usage for dashboards. Use 400 for body text and labels. Use 600 or 700 for headings and KPI numbers that need to stand out. Use 500 for subheadings that should be slightly heavier than body text but not as heavy as main headings. Never use font-weight: bold on body text at small sizes, because it reduces readability. Bold is for emphasis and hierarchy, not for entire paragraphs.

4. line-height: Controlling Vertical Spacing

Line-height controls the vertical space between lines of text. It is one of the most important properties for readability, and it is also one of the most commonly misused.

Unitless numbers: the best practice. When you set line-height as a unitless number, like 1.5 or 1.7, it means the line height is 1.5 times the current font-size. If the font-size is 16px, the line height becomes 24px. If the font-size is 24px, the line height becomes 36px. The value scales proportionally with the text, which is exactly what you want. This is the recommended approach:

body {
  font-size: 1rem;
  line-height: 1.7;
}

Why not use pixels or ems for line-height? If you write line-height: 24px, the spacing stays fixed at 24px even if a child element has a larger font-size, causing the lines to overlap. If you write line-height: 1.5em, the value is calculated once based on the parent's font-size and then inherited as a fixed pixel value by children, which causes the same overlapping problem. Only unitless line-height is inherited as a ratio, so children calculate their own line height based on their own font-size.

Practical values. For body text, 1.5 to 1.7 is the comfortable reading range. For headings, 1.2 to 1.4 is typical because headings have larger font sizes and do not need as much relative spacing. For data tables and dense dashboard content, 1.4 keeps things tight without feeling cramped. For marketing copy and long articles, 1.8 or even 2.0 gives the text room to breathe.

5. letter-spacing: Controlling Horizontal Spacing

Letter-spacing, also called tracking in typography, controls the space between individual characters. Small adjustments can dramatically change the feel of text.

Positive values spread characters apart. This is useful for uppercase labels, navigation links, and small text that needs to feel airy and elegant:

.label {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

Negative values pull characters closer. This is sometimes used on very large display text to make the letters feel more tightly knit, but it requires a font designed for tight spacing. Use negative letter-spacing sparingly and test carefully, because it can make text hard to read or even cause characters to overlap at certain sizes.

Practical usage for dashboards. Use small positive letter-spacing, 0.02em to 0.05em, on uppercase category labels and KPI card titles. Use normal letter-spacing, 0, for body text and data values. Never apply letter-spacing to monospace fonts used for code or data, because their fixed-width design depends on consistent character spacing.

Typography design and letterforms

6. Google Fonts Import

The fonts installed on your computer are limited. Google Fonts is a free library of over 1,400 typefaces that you can load into any web page with a single line of code. Using a custom font is one of the fastest ways to make a dashboard look distinctive and professional.

Method one: link in HTML head. Go to fonts.google.com, search for a font like Inter or Open Sans, select the weights you need, and copy the link tag provided by Google. Paste it into the head section of your HTML:

Then reference the font in your CSS:

body {
  font-family: 'Inter', sans-serif;
}

Method two: @import in CSS. You can also import Google Fonts directly inside your CSS file:

@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap');

body {
  font-family: 'Inter', sans-serif;
}

The @import method is convenient when you have a single CSS file and want to keep everything in one place. However, @import blocks CSS parsing until the font file is downloaded, which can delay the rendering of your page. The link tag in HTML is generally preferred for performance because it allows the browser to download the font in parallel with other resources.

Choosing weights wisely. Every weight you add increases the download size. If you only use 400 and 700 in your design, do not import 100, 200, 300, 500, 600, 800, and 900. The user's browser downloads every weight you specify, even if you never use them. For a typical dashboard, 400 for body text, 600 for subheadings, and 700 for main headings is sufficient.

The display=swap parameter. Notice the &display=swap at the end of the Google Fonts URL. This tells the browser to render text immediately using a fallback system font, then swap in the custom font once it has downloaded. Without this parameter, the browser might hide all text until the font loads, creating an invisible page for several seconds. Always include display=swap for any font used for body text.

7. text-align, text-decoration, and text-transform

These three properties handle the alignment, visual styling, and case transformation of text. They are simple individually but powerful in combination.

text-align: horizontal alignment. The values are left, right, center, and justify. left is the default for left-to-right languages like English. right aligns text to the right edge, useful for numeric data in tables so that decimal points line up. center aligns text to the middle, appropriate for headings and short labels but exhausting to read in long paragraphs. justify spreads text evenly across the full width by adjusting word spacing, which is standard in print newspapers but generally avoided on the web because it creates uneven gaps between words:

.kpi-value {
  text-align: right;
  font-size: 2rem;
  font-weight: 700;
}

.dashboard-title {
  text-align: center;
  font-size: 1.5rem;
}

text-decoration: adding or removing lines. The values include none, underline, overline, and line-through. The most common use is removing the default underline from links:

a {
  text-decoration: none;
}

For data dashboards, underline is rarely used because it competes with borders and gridlines. If you need to indicate a clickable element, use color, cursor: pointer, and hover states instead. line-through is useful for showing deleted or deprecated values, like an old price next to a new discounted price:

.old-price {
  text-decoration: line-through;
  color: #999;
}

text-transform: changing case. The values are none, uppercase, lowercase, and capitalize. uppercase converts every letter to capitals, which is the standard style for small labels, navigation items, and button text in modern interfaces:

.nav-item {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

lowercase is rarely used for display but can be useful for normalizing user input. capitalize makes the first letter of each word uppercase, like a book title: "Monthly Sales Report". This is useful for headings generated from database values that might be stored in lowercase or mixed case.

A practical habit: never type text in all caps manually. Always type in normal sentence case and use text-transform: uppercase in CSS. This keeps your HTML content semantically correct and accessible, because screen readers pronounce all-caps text as individual letters instead of words. CSS handles the visual presentation without corrupting the underlying content.

Text alignment and web design

Quick recap: font-family sets the typeface with fallback stacks, always end with a generic family · font-size controls text height, use rems for accessibility and scalability, reserve pixels for non-scaling elements · font-weight uses 400 for normal, 600-700 for headings, numeric values for precise control · line-height should be unitless, 1.5-1.7 for body text, so it scales with font-size · letter-spacing adds or removes space between characters, use small positive values for uppercase labels · Import Google Fonts via link tag in HTML head with &display=swap, choose only the weights you need · text-align controls horizontal alignment, right for numbers, center for short headings · text-decoration adds or removes lines, none for links, line-through for deprecated values · text-transform changes case in CSS, uppercase for labels, capitalize for titles, never type caps manually.

Using AI to Move Faster in CSS Typography

Typography is both an art and a science. The properties are simple, but choosing the right combination of font, size, weight, spacing, and alignment for a specific context takes experience. AI can accelerate that experience by suggesting proven combinations, generating responsive type scales, and catching accessibility mistakes before they reach production.

1. Generate a complete typographic scale with AI.
Instead of guessing font sizes for your dashboard headings, body text, captions, and labels, ask Copilot or ChatGPT: "Generate a CSS typographic scale for a data dashboard using rem units. I need sizes for a page title, section heading, card title, body text, small label, and data value. Use a 1.25 ratio between steps." AI will produce a harmonious scale where each level is 1.25 times the previous, creating visual hierarchy without arbitrary jumps. The ratio 1.25 is the major third in music theory and produces balanced, professional-looking type scales used by design systems like Material Design and Tailwind CSS.

2. Ask AI to suggest font pairings for dashboards.
If you are unsure whether to use Inter, Roboto, or Open Sans for your dashboard, describe your project to AI: "I am building a financial dashboard with dense data tables, KPI cards, and charts. Should I use a single font family for everything, or pair a sans-serif for UI elements with a serif for headings? Recommend specific Google Fonts and explain why." AI will explain that a single sans-serif family like Inter is usually best for data-heavy interfaces because it maintains consistency and reduces cognitive load, but it might suggest pairing Inter for data with Merriweather for report-style headings if your dashboard includes long-form narrative sections.

3. Use AI to catch accessibility issues in your CSS.
Paste your CSS into an AI assistant and ask: "Review this CSS for typography accessibility issues. Check for font sizes below 16px on body text, line-height below 1.5, missing generic font fallbacks, and insufficient color contrast." AI will flag problems like font-size: 12px on body text, which fails WCAG accessibility guidelines, or a font stack that ends with a specific font name instead of sans-serif. Fixing these before deployment prevents complaints from users with visual impairments and avoids legal accessibility compliance issues in enterprise environments.

4. Generate responsive clamp() values for fluid typography.
Writing clamp() values that feel right across all screen sizes requires trial and error. Ask AI: "Write CSS clamp() values for a dashboard where the page title should be 1.5rem on mobile, 2.5rem on desktop, and scale smoothly between. The body text should be 1rem minimum, 1.125rem preferred, and 1.25rem maximum." AI will generate the exact clamp syntax with correct calculations. You paste it into your CSS and test on a few devices. This removes the arithmetic guesswork from responsive typography.

5. Verify AI suggestions against real browser behavior.
AI can suggest font-weight: 250 or line-height: 1.05, which might look correct in theory but render poorly in actual browsers. Not all browsers support every font weight equally, and extremely tight line-height can cause text to overlap on certain operating systems. Always test AI-generated typography in Chrome, Firefox, and Safari, and on both desktop and mobile, before committing. AI gives you a strong starting point. Your eyes and your users' devices give you the final verdict.

A habit worth building from this lesson onward: whenever you start a new project, define your typographic system in a single CSS file or section before writing any other styles. Decide your font family, your type scale in rems, your line-height ratios, and your letter-spacing rules. Document them in comments. Then use AI to refine and expand that system, not to invent it from scratch. A consistent typographic foundation makes every other design decision easier, and AI is most useful when it is improving a system you have already thought through.

Next lesson: the CSS box model, margins, padding, borders, and display properties.

Complete this lesson

Mark as complete to track your progress