Type something to search...
What is a baseline grid and how do you use one on the web?

What is a baseline grid and how do you use one on the web?

A baseline grid is a set of evenly spaced horizontal lines, usually one body line height apart, on which every line of text in a layout sits. Body copy, headings, captions and sidebars all align to the same lines, so text in neighbouring columns lines up across the page. It comes from print, where designers have used it for centuries to keep pages orderly. On the web you can build one with CSS by making every line height and every vertical space a multiple of the grid unit, and modern properties such as text-box-trim make the alignment more precise. It's useful for multi-column layouts, editorial designs and design systems, but it's fragile, so most sites are better served by a lighter version.

A baseline grid is the strictest form of vertical rhythm. Done well, it gives text-heavy pages a quiet, engineered precision. Done carelessly, it creates odd gaps under headings and makes every new component a maths problem. In this article you'll learn what the baseline actually is, why web text doesn't naturally sit on a grid, how to build a grid with the rlh unit and custom properties, how to trim the extra space above and below text, how to show a grid overlay while you work, and when a baseline grid is worth the effort.

What the Baseline Is

The baseline is the invisible line that most letters sit on. The bottoms of a, x and n rest on it; descenders on g, p and y drop below it. In print, the leading (the distance from one baseline to the next) is the fundamental measurement of a text block, and a baseline grid is simply that leading repeated down the whole page.

If your body text is 16px on a 24px leading, the baseline grid has a line every 24px. Every line of body text must sit on one of those lines. A 32px heading can't use a 24px line height comfortably, so it might use 48px, two grid lines, and still land its baseline on the grid.

Why Web Text Doesn't Sit on a Grid by Default

CSS doesn't position text by its baseline. It positions line boxes. Each line box is as tall as the computed line-height, and the font's glyphs are centred vertically inside it, with the extra space (the half-leading) split above and below.

That has two consequences:

  1. The first baseline is not at the top of the element: Where the baseline ends up depends on the font's ascent and descent metrics, which vary from font to font.
  2. Different font sizes put the baseline in different places: A 16px paragraph and a 20px quote with the same 24px line height have their baselines at slightly different offsets inside their line boxes.

So even if every line height and margin is a multiple of 24px, the baselines of mixed font sizes won't line up perfectly. Line boxes will be on the grid, but the text within them may sit a pixel or two above or below it. For a lot of designs that's fine. For a strict baseline grid, you need to correct for it.

Build the Grid Unit

Start with a single unit and derive everything from it. This example uses a 16px base and a 24px grid:

:root {
  --baseline: 1.5rem; /* 24px at the default 16px root size */
}

html {
  font-size: 100%;
  line-height: 1.5;
}

body {
  margin: 0;
}

The rlh unit, supported in current versions of all major browsers, equals the root element's line height, so 1rlh is the same as var(--baseline) here. Use whichever is clearer to your team.

Set Line Heights in Grid Units

Give every text style a line height that is a whole number of grid units. Don't use unitless ratios for these, because a ratio produces a different absolute value for every font size.

body {
  font-size: 1rem;           /* 16px */
  line-height: 1rlh;         /* 24px */
}

h1 {
  font-size: 2.5rem;         /* 40px */
  line-height: 2rlh;         /* 48px */
}

h2 {
  font-size: 1.75rem;        /* 28px */
  line-height: 1.5rlh;       /* 36px, half-grid */
}

h3 {
  font-size: 1.25rem;        /* 20px */
  line-height: 1rlh;         /* 24px */
}

small,
figcaption {
  font-size: 0.875rem;       /* 14px */
  line-height: 1rlh;         /* 24px */
}

Some designers allow half-grid steps, as in the h2 above, which still keeps every block a multiple of 12px. A half-grid gives you more freedom with heading sizes without abandoning alignment.

Set Margins in Grid Units

Margins must follow the same rule. If a heading has 1.5 units of line height and wraps onto two lines, it's 3 units tall, so the total stays on the grid as long as its margins are whole or half units too:

p,
ul,
ol,
blockquote {
  margin-block: 0 1rlh;
}

h1 {
  margin-block: 0 1rlh;
}

h2 {
  margin-block: 2rlh 0.5rlh;
}

h3 {
  margin-block: 1.5rlh 0.5rlh;
}

Notice that the h2 uses 2 units above and half a unit below, then has 1.5 units of line height per line. A single-line h2 takes 4 units in total, so whatever comes after it is back on a whole grid line.

Trim the Space Above and Below Text

To get baselines exactly on the grid rather than just line boxes, you need to remove the extra space that the font's metrics and the half-leading add above the first line and below the last.

Using text-box-trim

CSS now has properties designed for this, from the CSS Inline Layout specification:

h1,
h2,
h3,
p {
  text-box-trim: trim-both;
  text-box-edge: cap alphabetic;
}
  • text-box-trim chooses which sides to trim: trim-start, trim-end, trim-both or none.
  • text-box-edge chooses where to trim to. cap alphabetic trims the top to the cap height and the bottom to the alphabetic baseline.
  • text-box is a shorthand: text-box: trim-both cap alphabetic;.

With this in place, the bottom edge of the box is the baseline of the last line. If you then add margins in whole grid units, baselines land on grid lines. At the time of writing, text-box-trim is supported in Chromium-based browsers and Safari, but not yet in Firefox, so treat it as a progressive enhancement and test the fallback.

Using Font Metrics

Before text-box-trim, the usual method was to calculate the offset from the font's metrics and shift the text with negative margins or a small position: relative nudge. Tools such as Capsize generate this CSS for a given font. The idea looks like this:

/* Offsets for one specific font at 16px with a 24px line height.
   These numbers come from the font's metrics and differ for every font. */
.capsize-body::before {
  content: "";
  display: table;
  margin-block-end: -0.4375em;
}

.capsize-body::after {
  content: "";
  display: table;
  margin-block-start: -0.4em;
}

The pseudo-elements pull the box edges in to the cap height and the baseline. It works in every browser, but the values must be recalculated if you change the font, and a fallback font with different metrics will sit slightly off the grid while your web font loads.

You can read the metrics you need from the font file with fonttools:

pip install fonttools
python -c "
from fontTools.ttLib import TTFont
f = TTFont('BodyFont-Regular.woff2')
print('unitsPerEm', f['head'].unitsPerEm)
print('ascender', f['hhea'].ascent)
print('descender', f['hhea'].descent)
print('capHeight', f['OS/2'].sCapHeight)
print('xHeight', f['OS/2'].sxHeight)
"

Example output for one font (your numbers will differ):

unitsPerEm 2048
ascender 1984
descender -494
capHeight 1490
xHeight 1118

Reading .woff2 files with fonttools also needs the Brotli package (pip install brotli). Divide each value by unitsPerEm to get the measurement as a fraction of the font size.

Show a Grid Overlay While You Work

You can't keep a grid if you can't see it. A repeating gradient on a pseudo-element draws the lines without affecting layout:

.show-baseline {
  position: relative;
}

.show-baseline::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image: linear-gradient(
    to bottom,
    transparent calc(1rlh - 1px),
    rgb(255 0 80 / 0.35) calc(1rlh - 1px)
  );
  background-size: 100% 1rlh;
  z-index: 10;
}

Toggle it from the console when you need it:

document.body.classList.toggle("show-baseline");

Each pink line marks the bottom of a grid unit. With text-box-trim applied, the baselines of your text should rest on these lines. Without it, the line boxes will align but the letters will sit a little above them, consistently.

Where Baseline Grids Break

Several things will push content off the grid, and you need a strategy for each.

  • Images and video: Their heights are set by their aspect ratio and width, not by your grid. You can wrap them in a container whose height is rounded up to a grid multiple, or accept that media resets the grid and keep the space below it in whole units.
  • Borders: A 1px top and bottom border makes a box 2px taller. Use box-shadow or outline for visual edges, or subtract the border from the padding with calc().
  • Form controls and buttons: Browsers style these with their own line heights and padding. Set an explicit height in grid units, such as height: 2rlh, and align the text inside with flexbox.
  • Third-party embeds: You can't control their heights. Treat them like images.
  • User font size changes: If everything is in rem or rlh, the whole grid scales together. If anything is in pixels, it drifts.
  • Fallback fonts: Different metrics place the baseline differently until the web font loads. Matching fallback metrics with size-adjust, ascent-override and descent-override in your @font-face rules reduces the jump.

Here's a pattern for snapping a media container to the grid. It rounds the height up to the next whole unit using the CSS round() function, which is supported in current major browsers:

.grid-media {
  height: round(up, var(--media-height, 300px), 1rlh);
  overflow: hidden;
}

.grid-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

When a Baseline Grid Is Worth It

A strict baseline grid earns its keep in a few situations:

  • Multi-column text: When readers see two or more columns side by side, misaligned lines are obvious. A grid makes the columns line up across the gutter.
  • Editorial and long-form layouts: Magazines, reports and books moved to the web benefit from the order a grid brings, especially with sidebars and pull quotes beside the main text.
  • Design systems with strict specs: If design files are built on a 4px or 8px baseline, matching it in code reduces the gap between design and build.

For a typical marketing site, documentation or an app interface, a strict grid usually isn't worth the effort. Vertical rhythm, where spacing comes from one consistent unit but baselines aren't individually aligned, gives most of the benefit with far less maintenance.

A Compromise: the 4px Grid

Many product teams use a 4px (0.25rem) grid instead of a full line-height grid. Every line height, margin and padding is a multiple of 4px. Text doesn't align across columns, but spacing stays consistent and the maths is easy:

:root {
  --grid: 0.25rem;
}

body {
  line-height: calc(var(--grid) * 6);   /* 24px */
}

.card {
  padding: calc(var(--grid) * 4);       /* 16px */
  margin-block-end: calc(var(--grid) * 6);
}

This is the approach behind many popular design systems and utility frameworks, and it's a sensible default when you want consistency without a strict grid.


FAQ: Baseline Grids

A baseline grid aligns the baseline of every line of text to fixed horizontal lines. Vertical rhythm only requires that spacing comes from one consistent unit. A baseline grid is a stricter form of vertical rhythm.

Use the line height of your body text, for example 24px for 16px text with a line height of 1.5. Some designers use half of that as the grid to allow more flexibility with heading sizes.

CSS centres glyphs inside each line box, and the position of the baseline depends on the font's metrics. Line boxes can be on the grid while the letters sit slightly above it. The text-box-trim property, or offsets calculated from font metrics, fixes this.

At the time of writing, Chromium-based browsers such as Chrome and Edge and recent versions of Safari support it. Firefox does not yet. Use it as a progressive enhancement and check current support before relying on it.

Either crop images into containers whose height is a whole number of grid units, for example with the CSS round() function and object-fit, or let images break the grid and make sure the space after them is a whole number of units.

No. It's most useful for multi-column and editorial layouts. Most sites get enough consistency from vertical rhythm or a 4px spacing grid, which are much easier to maintain.


Conclusion

A baseline grid places every line of text on evenly spaced horizontal lines so that columns, sidebars and headings align across the page. On the web you build it by giving every text style a line height in whole grid units, keeping every margin in the same units, and, where you need exact alignment, trimming the space above and below text with text-box-trim or metric-based offsets. A gradient overlay makes the grid visible while you work.

Because images, borders, form controls and fallback fonts all push content off the grid, a strict baseline grid takes ongoing care. Use it where alignment across columns is part of the design, and choose vertical rhythm or a simple 4px grid everywhere else. Either way, the principle is the same: every vertical space should come from one system.

Share :

Related Posts

How to make typography accessible?

How to make typography accessible?

You make typography accessible by choosing clear typefaces, setting text in relative units so it scales with user preferences, giving it enough colou

Dive Deeper
What are the parts of a letterform?

What are the parts of a letterform?

A letterform is the shape of a single letter, and typographers break it down into named parts. The main ones are the stem (the main vertical

Dive Deeper
What are ascenders, descenders and the baseline?

What are ascenders, descenders and the baseline?

The baseline is the invisible line that letters sit on. Ascenders are the parts of lowercase letters that rise above the x-height, such as th

Dive Deeper