Optimal reading column width checker
Enter a 16 px font and a 560 px column and you get 70 characters per line, inside the 45 to 75 range that keeps long reading comfortable. Check each breakpoint before you commit to a layout. 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
- Column width
- 560
- Characters per line
- 70
- Assessment
- recommended
- Recommended min
- 45
- Recommended max
- 75
Readable typography depends on more than choosing an attractive font. A text column that is too wide can make the reader lose their place while moving from one line to the next, while a very narrow column interrupts sentences with constant wrapping. This checker uses your font size and column width to estimate characters per line, then shows whether that estimate falls inside the commonly recommended range of 45 to 75 characters. It is a quick planning aid for articles, documentation, newsletters, dashboards, and other sustained reading layouts.
How to enter your typography measurements
Enter the body font size and the width of the actual text column in CSS pixels. Use the width available to the text itself, after subtracting container padding, borders, side notes, or any space reserved for adjacent controls. For example, a content card may be 640 pixels wide but provide only 576 pixels for its paragraphs after 32 pixels of padding on each side.
The font size should be the computed body size, not a browser zoom percentage, a heading size, or a design-token name. Both values must be positive finite numbers, and a non-positive font size is rejected because it cannot describe readable rendered text. Keeping both measurements in pixels lets the ratio remain consistent and easy to compare.
If your design uses rem units, multiply them by the root font size first, or inspect the computed values in browser developer tools. Run separate checks for desktop, tablet, and mobile breakpoints because a responsive column can move between narrow, recommended, and wide even when its font size stays unchanged. The output repeats both inputs, making it straightforward to record which breakpoint and typography setting produced each assessment.
Understand the character-per-line estimate
The checker estimates an average character as one half of an em, meaning half the supplied font size. It divides the column width by that estimated character width and reports the resulting characters per line to one decimal place. This is deliberately an approximation: real glyph widths depend on the typeface, weight, language, punctuation, letter spacing, and the particular words in a paragraph.
A condensed sans serif may fit more characters than the estimate, while a wide display face may fit fewer. The tool therefore supports early layout decisions and consistent design reviews; it does not replace measuring a representative passage in the final font. Classification uses the unrounded result and treats 45 and 75 as inclusive boundaries.
Values below 45 are marked too narrow, values above 75 are marked too wide, and values in between are marked recommended. The response also exposes the assumed 0.5-em average and both recommended limits, so the method is never hidden. When a result sits close to either boundary, test real content and consider the estimate a prompt for visual review rather than a rigid pass-or-fail accessibility rule.
Turn the result into a practical layout decision
A recommended result suggests that the relationship between type size and measure is suitable for sustained reading, but it is only one part of a comfortable text system. Review line height, paragraph spacing, contrast, font rendering, and the needs of the intended audience alongside this value. If the result is too wide, reduce the text container's maximum width, increase the font size where appropriate, or introduce a multi-column layout only when the reading order remains clear.
If it is too narrow, allow the column more horizontal space, reduce excessive side padding, or reconsider whether the font size is disproportionately large for that component. Avoid shrinking body text merely to force a passing result, especially on small screens. Use the checker during design-token development to compare proposed container sizes, and run it again after implementation because grid gaps and nested padding can change the effective width.
For multilingual sites, validate representative content in every script even though this numeric estimate remains useful as a shared baseline.
What you can do with it
Set an article max-width
Compare candidate content widths against the body font size before choosing a desktop max-width.
Audit responsive breakpoints
Check desktop, tablet, and mobile column values to find layouts that become too narrow or too wide.
Review design-system tokens
Test typography and container tokens together so documentation and product teams share a readable baseline.
FAQ
What range is considered recommended?
The checker treats 45 through 75 estimated characters per line, including both boundaries, as recommended.
How is characters per line calculated?
It assumes an average character width of 0.5 em and divides the column width by half of the font size.
Is this an exact measurement for my font?
No. Glyph widths vary by font, weight, language, spacing, and content, so the result is a planning estimate.
Is a 560 px column too wide for 16 px body text?
No. At 16 px the checker estimates each character at 8 px, so 560 px holds about 70 characters per line, which is marked recommended because it sits between 45 and 75.
What width should I enter when my content box has padding?
Enter only the space the paragraphs actually use. A card 640 px wide with 32 px of padding on each side leaves 576 px, and that is the figure to check, not the outer width.
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/doc/reading-column-width-check \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"font_size":16,"column_width":560}'const res = await fetch("https://api.kit.forhosting.com/doc/reading-column-width-check", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"font_size": 16,
"column_width": 560
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/doc/reading-column-width-check",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"font_size": 16,
"column_width": 560
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/doc/reading-column-width-check", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"font_size":16,"column_width":560}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"font_size":16,"column_width":560}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/doc/reading-column-width-check", 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,
"column_width": 560
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "doc.reading_column_width_check",
"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.
Limits
max_mb | 25 |
max_pages | 200 |
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
Turn the result into a practical layout decision
The browser version is free for interactive checks, while automated API requests cost $0.002 each and can be included in layout audits or design-system quality checks.
Technical questions
What happens if the font size is zero or negative?
The request fails with an invalid_input error because font size must be positive.
What does an API request cost?
Each API request costs $0.002; interactive use in the browser is free.