Baseline grid line height
16 px type with a ratio of 1.5 on an 8 px grid gives a 24 px line height: exactly 3 grid rows, so every line sits on the same rails. When the ideal misses the grid, it snaps to a whole number of rows. Free in your browser.
- Free
- Runs in your browser
- No sign-up
- Your data stays on your device
Run — free
Worked example
- Font size
- 16
- Grid
- 8
- Preferred ratio
- 1.5
- Snap
- nearest
- Ideal line height
- 24
- Line height
- 24
- Ratio
- 1.5
A baseline grid keeps every line of text sitting on the same invisible horizontal rails so paragraphs, captions, and multi-column layouts share one vertical rhythm from the top of the page to the footer. Designers and front-end engineers pick a grid unit—often four, six, or eight pixels—and want a line-height that is an exact multiple of that unit, not a floating ratio that drifts half a pixel each line. This baseline grid line height calculator takes your font size, preferred unitless ratio, and grid row height, then snaps the ideal line box onto the nearest (or ceiling, or floor) whole number of grid rows. You get the snapped line-height in pixels, the effective ratio to paste into CSS, how many grid rows that line occupies, and whether the ideal value already landed on the grid.
How baseline-grid line-height snapping works
Start from the familiar unitless line-height rule: multiply font size by a preferred ratio such as one point five to obtain an ideal line box in the same unit as the font (almost always CSS pixels). That product is comfortable for reading but rarely lands exactly on your baseline grid. Divide the ideal line-height by the grid row height to learn how many rows the line wants to occupy; then apply a snap mode.
Nearest rounds to the closest whole row count, which is the default for body copy when you want the smallest visual change from the preferred ratio. Up (ceiling) always grows the line box so text never feels tighter than the ideal—useful when legal footnotes or long measure lines need breathing room. Down (floor) shrinks toward the grid when you must protect a tight vertical budget such as a card height or a print column.
After snapping, multiply the integer row count by the grid unit to get the final line-height, and divide by font size to recover the unitless ratio you can drop into a CSS custom property. A row count of at least one is enforced so pathological inputs cannot collapse line-height to zero.
Where snapping line height to a grid pays off
Design systems generate spacing and type scales from a single grid constant; calling this calculator when authors add a new size keeps every line-height token on the rails without a spreadsheet. Print and PDF pipelines that map CSS to fixed page grids use the same snap logic so on-screen previews match the press sheet. Failed validation does not consume balance.
Keep preferred ratios modest, pin goldens on the rounded fields, and you get reproducible vertical rhythm for design tokens, edge workers, and style-guide generators without standing up a layout engine of your own.
What you can do with it
Design-token and type-scale generation
When you add a new font size to a design system, snap its preferred ratio onto the shared baseline grid so every line-height token stays an integer multiple of the grid unit.
Multi-column and card layouts
Align body, caption, and heading line boxes across columns and stacked cards by computing snapped line-heights for each size against one grid.
Print and PDF vertical rhythm
Map screen type scales to a fixed print baseline so CSS-to-PDF pipelines keep paragraph spacing consistent with the page grid.
FAQ
What is the difference between nearest, up, and down snap?
Nearest rounds the ideal line box to the closest whole number of grid rows. Up always ceilings (looser leading). Down floors (tighter leading). Row count is never less than one.
How is this different from a simple line-height calculator?
A plain line-height calculator multiplies font size by a ratio only. This tool also snaps that product onto a baseline grid so vertical rhythm stays consistent across sizes and columns.
Which grid unit should I choose?
Designers usually pick 4, 6 or 8 pixels and build all spacing from that one number. Enter the same unit here and every line height you get back is an exact multiple of it, instead of a ratio that drifts by half a pixel per line.
How do I know if my preferred ratio already fits the grid?
The result tells you when the ideal line height already lands on a whole number of rows. Then nothing changes: 16 px type at 1.5 on an 8 px grid stays at 24 px, three rows, with the ratio untouched.
Should I use the pixel value or the ratio in my styles?
Either keeps text on the grid. Use the snapped line height in pixels, or the effective ratio, which is that height divided by the font size, if your style sheet uses unitless line heights.
Related tools
For developers — API access
Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.
API endpoint
Prefer to automate it? One authenticated POST creates the task; the result comes back by webhook or a signed link. The same capability also runs here on the web, by email and from Telegram — and soon from our app too.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/str/baseline-grid \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"font_size":16,"grid":8}'const res = await fetch("https://api.kit.forhosting.com/str/baseline-grid", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"font_size": 16,
"grid": 8
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/str/baseline-grid",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"font_size": 16,
"grid": 8
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/str/baseline-grid", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"font_size":16,"grid":8}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"font_size":16,"grid":8}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/str/baseline-grid", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"font_size": 16,
"grid": 8
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "str.baseline_grid",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.
Pricing
Published price — no tokens, no invented credits. A failed task is never charged.
Errors
| HTTP | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid API key. |
402 | insufficient_balance | Your balance doesn't cover the task price. |
404 | unknown_type | That task type doesn't exist. |
429 | rate_limited | Too many requests. Use the webhook instead of polling. |
Technical notes
How baseline-grid line-height snapping works
When the ideal product already equals a whole number of rows, the response marks on_grid true so token pipelines can skip a rewrite.
Input contract, response fields, and validation
Eighteen pixel type on the same eight pixel grid with ratio one point five yields ideal twenty-seven, which snaps nearest to twenty-four (three rows, ratio about one point three three) or up to thirty-two (four rows) depending on snap. POST a JSON body with two required positive finite numbers: font_size (CSS pixels for the text you are sizing) and grid (the baseline row height in the same unit). Optionally send preferred_ratio, defaulting to one point five when omitted, and snap as nearest, up, or down—aliases such as round, ceil, and floor are accepted. Numeric fields may arrive as JSON numbers or decimal strings; missing values, zero, negatives, NaN, and Infinity fail with invalid_input and are not billed. On success the payload echoes font_size, grid, preferred_ratio, and snap; reports ideal_line_height before snapping; returns line_height and ratio after snapping; includes integer grid_rows; sets on_grid when the ideal already matched a multiple of the grid; and provides a short formula string for documentation. Example: sixteen pixel type on an eight pixel grid with preferred ratio one point five yields ideal twenty-four, which is exactly three rows, so line_height stays twenty-four and ratio stays one point five. Pair the numbers with your own rem conversion if the root font size differs; this endpoint works in raw pixels so results stay deterministic across environments.
Where a baseline grid line-height API earns its keep
Component libraries that render multi-column articles, product cards, or documentation sidebars need matching baselines across breakpoints—batching font sizes through the API yields a stable table of snapped ratios for Storybook and visual regression.
Technical questions
How do I calculate a baseline-grid line height?
Send positive font_size and grid (and optionally preferred_ratio, default 1.5, and snap: nearest, up, or down). The API returns line_height as an integer multiple of the grid and the effective unitless ratio.
What units should I use for font_size and grid?
Use the same unit for both—typically CSS pixels. The math is unit-agnostic as long as both inputs share a scale; rem conversion is left to your root font size.
What does the baseline grid line height tool cost?
The browser tool is free. API requests use prepaid KIT balance at $0.002 per successful call; invalid input is not billed.