Websites that read in the terminal: the TermWeb standard
I have never dared to write or define a standard for the web, let alone one about design. I am more of a technical person than anything else. But for fun, this time I am going to do it. I am going to define a design and development pattern that gives a consistent layout and user experience across every terminal browser, easy to navigate by tabbing, respecting verticality and without depending on CSS, JavaScript or images. And I am going to do it with clear, verifiable rules. I will call this standard TermWeb.
If you want to see where the idea comes from, I recommend reading my article on how to design websites for terminal browsers. There I dig into which tags are the right ones, the limitations and the common ground between the different terminal web browsers. In the end I gather a set of rules and best practices, which I expand and formalize here.
A heads-up! This is not a committee standard, but my humble proposal built from empirical data and a collection of design patterns that already exist.
0. Principles and scope
The rules follow the RFC convention. MUST is mandatory, SHOULD is recommended and MAY is optional. A page is conformant if it meets every MUST.
And there are two widths that govern everything. Normal text flows and the engine itself reflows it, but whatever you fix by hand (ASCII art, navigation lines, tables, <pre> and code blocks) has two limits:
- MUST fit in 80 columns: the hard limit, the desktop terminal.
- SHOULD fit in 40 columns: the safe width, the one that holds on a phone in portrait and on narrow terminals. It matches the heir of the 79 columns on mobile and the lower bound of the readable range, 30 to 40 characters per line.
1. Canonical document order
In the terminal there is no float, no flex, no grid, no order. Whatever you put first in the HTML comes first on screen. Full stop. So every page MUST follow this order in the code:
- Skip-to-content link
- Header: site name and, at most, one short navigation line
- Breadcrumbs (except on the home page)
- Main content
- Complementary content (related, tags)
- Pagination, if any
- Full navigation
- Footer
The content MUST start in the first lines of the screen. The long navigation and the footer go at the end. There are no columns or sidebars: whatever would be a sidebar goes in point 5.
The header, nav, main, aside and footer tags MUST be used for their semantic value, but make no mistake: they do not add a single line break. The visual separation comes from paragraphs, headings and <hr>.
2. Header and logo
The first thing that shows up. Make it text, make it fit and make it lead home.
- 2.1. The site name MUST be text and link to the home page.
- 2.2. If the logo is an image, its
altMUST be the site name. - 2.3. The tagline, if any, SHOULD take a single line.
- 2.4. An ASCII-art logo MAY go in
<pre>, with 6 lines at most. It MUST fit in 80 columns and SHOULD fit in 40, so it does not blow up on mobile. - 2.5. Every page MUST have a descriptive
<title>: lynx and links show it at the top and all of them use it to identify the page. - 2.6. The document MUST declare
<meta charset="utf-8">and SHOULD be served over HTTPS.
3. Navigation
Nobody wants to tab through thirty menu links before reaching the first sentence. Navigation gets pruned.
- 3.1. Header navigation MUST NOT exceed 5 links or a line of 80 columns, and SHOULD fit in 40.
- 3.2. The full navigation MUST go at the end and MAY act as a site map.
- 3.3. There MUST NOT be dropdowns or submenus: hierarchy is solved with index pages per section.
- 3.4. Inner pages MUST show breadcrumbs:
Home > Section > Page. - 3.5. The skip link MUST be the first link and MUST always be visible. Hiding it with a CSS class does not work: all five engines show it anyway.
4. Content
If the structure lives in the tags and not in the CSS, it reads anywhere.
- 4.1. Structure MUST be marked with tags, not styles:
h1–h6,ul/ol,dl,blockquote,preandcode. Never a<div class="title">. - 4.2. Every page MUST have a single
h1and a heading hierarchy with no gaps. - 4.3. Paragraphs MUST be real
<p>, not blocks separated with<br>. - 4.4. Pages with more than 3 sections SHOULD start with an index linked to anchors.
- 4.5. The publication date MUST be visible text.
- 4.6.
<details>MUST NOT be used to hide content: no engine folds it and it always shows everything.
5. Links
In the terminal, links are walked one after another with the Tab key. Out of their sentence, they still have to mean something.
- 5.1. Each link's text MUST make sense out of context. "Here" or "read more" with no complement do not count.
- 5.2. Links to other formats SHOULD say so:
Manual (PDF, 2 MB). - 5.3. If you use relative links, you SHOULD declare
<base href>, which all five engines respect.
6. Images and multimedia
Only EWW always paints the image, and w3m only in capable terminals. In the other four engines, by default, the image is its alt. Let it sink in: the alt is not an accessibility extra, it is your content.
- 6.1. Every informative image MUST have an
altwritten as a sentence. Decorative ones MUST carry an explicitalt="", because a missingaltshows the file name. - 6.2. Critical information MUST NOT depend on an image, a color or an icon. Color MUST always be paired with text or a symbol ("Error:", an asterisk).
- 6.3. Images SHOULD offer
srcsetso the engine that does paint them picks the resolution. - 6.4. Icon fonts are forbidden.
- 6.5. Audio and video MUST offer a direct link to the file and a description or transcript.
- 6.6. An image embedded as a
data:URI is painted only by EWW; everywhere else you see itsalt, so it saves nothing over a normalsrcand bloats the HTML. It SHOULD NOT be used.
7. Tables
w3m and EWW draw a surprisingly decent ASCII grid. But a grid is not a layout.
- 7.1. Tables MUST be used only for data, never for layout.
- 7.2. Tables SHOULD have a single header row and MUST NOT be nested.
- 7.3.
colspanandrowspanSHOULD be avoided: lynx flattens them. - 7.4. A table MUST fit in 80 columns and SHOULD fit in 40, with few columns and short cells. If it does not fit, it SHOULD become a structured list.
8. Forms and interaction
GET and POST work in all five engines.
- 8.1. Every form MUST have
action,methodand a real submit button (<button type="submit">or<input type="submit">). - 8.2. Every field MUST have a
name, because the engines collect data byname, and an associated<label>. - 8.3. Validation MUST be done on the server, with errors as text at the start of the form.
- 8.4. After a POST, the server SHOULD respond with a redirect (the Post/Redirect/Get pattern).
- 8.5. There MUST NOT be a graphic CAPTCHA without a text alternative.
A minimal example, a coffee order:
<form action="/order" method="post">
<p><label>Your name <input type="text" name="name"></label></p>
<p><label>Quantity <input type="number" name="quantity" value="1"></label></p>
<p><label><input type="checkbox" name="no_milk" value="yes"> No milk</label></p>
<p><button type="submit">Order coffee</button></p>
</form>
It works the same in EWW as in Chrome, without a single line of JavaScript.
9. Dependencies
- 9.1. A page MUST NOT need JavaScript to show its content or work.
- 9.2. Reading the content MUST NOT require any third-party resource.
- 9.3. The site SHOULD offer an RSS or Atom feed.
10. Optional graphic layer
With CSS turned off, the page MUST still be readable. If it is not, the problem is not the browser, it is your HTML.
- 10.1. CSS MAY improve typography, spacing and color in graphic browsers.
- 10.2. CSS MUST NOT visually reorder elements (
order,grid-area, absolute positioning) relative to the code. - 10.3. What is in the HTML shows in the terminal. A
display:noneby class shows in all five engines, and an inline one is respected only by EWW and links. If something must not be seen, it MUST NOT be in the HTML. - 10.4. Text centering and alignment (
text-align) are applied only by elinks; in the other four the text goes left. No design MUST depend on them. - 10.5. Inline
colordepends on the terminal, and in many it does not even show. It works as an improvement, never as information (rule 6.2).
A real example
This is the skeleton of a conformant page; swap the content and you have anything from a blog to a shop:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Article title - My site</title>
</head>
<body id="top">
<a href="#content">Skip to content</a>
<header>
<p><a href="/">My site</a>, subtitle or short description</p>
<nav aria-label="Primary">
<p><a href="/">Home</a> | <a href="/blog/">Blog</a> | <a href="/about/">About</a></p>
</nav>
</header>
<nav aria-label="Breadcrumbs">
<p><a href="/blog/">Blog</a> > <a href="/blog/web/">Web</a> > Article</p>
</nav>
<main id="content">
<h1>Article title</h1>
<p>The first paragraph starts in the first lines of the screen.</p>
</main>
<hr>
<nav aria-label="All sections">
<p><a href="/">Home</a> | <a href="/blog/">Blog</a> | <a href="/projects/">Projects</a> | <a href="/about/">About</a> | <a href="/contact/">Contact</a> | <a href="/feed.xml">RSS</a></p>
</nav>
<footer>
<p>2026, Your name</p>
<p><a href="#top">Back to top</a></p>
</footer>
</body>
</html>
Two details that teach half the standard. The separator is an <hr>: you do not fix its width, each engine draws it to the width of its window, so it never runs off the screen. And the link lists go inside <p>, because <nav> does not add a single line break and, without the paragraph, the header and the breadcrumbs would stick together on the same row.
On the desktop at 80 columns it sits comfortably; on a phone at 40, the header and the breadcrumbs break into two lines and the <hr> gets shorter, but the order and the content do not move.
Swap the content for that of a real site and this is what the terminal reads. The Hacker News front page under these rules (I draw the links in brackets and the <hr> as a line of dashes, lynx style):
[Skip to content]
HACKER NEWS - Links and discussion for curious hackers
[new] | [past] | [ask] | [show] | [submit]
TOP STORIES
1. [Designing websites for terminal browsers]
(andros.dev)
312 points by [andros] 4 hours ago | [87 comments] | [upvote]
2. [Show HN: A static site generator in 400 lines of Elisp]
(github.com)
198 points by [tanrax] 6 hours ago | [42 comments] | [upvote]
3. [Why SQLite's website weighs only 70 KB]
(sqlite.org)
156 points by [drh_fan] 8 hours ago | [31 comments] | [upvote]
4. [Ask HN: Do you still browse with lynx?]
89 points by [oldschool] 9 hours ago | [120 comments] | [upvote]
[More stories »]
----------------------------------------
[new] | [past] | [comments] | [ask] | [show] | [jobs] | [submit]
[login] | [Guidelines] | [FAQ] | [API] | [Contact] | [RSS]
2026 - Y Combinator
[Back to top]
And an inner page, comments and a form included:
[Skip to content]
HACKER NEWS - Links and discussion for curious hackers
[new] | [past] | [ask] | [show] | [submit]
[Top] > [Stories] > Designing websites for terminal browsers
DESIGNING WEBSITES FOR TERMINAL BROWSERS
[Read the article] (andros.dev)
312 points by [andros] 4 hours ago | [upvote] | 87 comments
ADD A COMMENT
Comment:
[________________________________________]
[Post comment]
COMMENTS
* [rahulj] 3 hours ago | [upvote] | [reply]
I ran the validator against my blog: 94/100. It caught a jump
from h1 to h4 I had never noticed.
* [andros] 2 hours ago | [upvote] | [reply]
Thanks! That's exactly the kind of friction it's meant to
flag.
* [w3m_user] 3 hours ago | [upvote] | [reply]
Funny that HN itself scores 55 but reads fine in w3m.
----------------------------------------
[new] | [past] | [comments] | [ask] | [show] | [jobs] | [submit]
[login] | [Guidelines] | [FAQ] | [API] | [Contact] | [RSS]
2026 - Y Combinator
[Back to top]
Final notes
I am not going to say anything that has not been said before: HTML rules and everything else is presentation on top. Adapting a web page takes work, just like adapting it for mobile. Prioritizing a good terminal rendering is a design decision, not an accident: you have to write it well.
If you need some reference, you can use my humble script TerminalSpeed Insights as a first step, but do not treat it as the definitive validator: that is you.
Sources
- Web Design for Terminal Browsers, my previous article: the experiment with the five engines that almost all of this comes from (blocks 0, 1, 4, 6, 8 and 10).
- Justifying text by hand, now at 35 columns: the calculation of the safe width for mobile and the readable range (block 0).
- GOV.UK progressive enhancement: the HTML layer rules, the rest is enhancement (blocks 0 and 10).
- W3C WAI / WCAG: skip to content and meaningful order (blocks 1, 3 and 5).
- Viewable with Any Browser: text first, without depending on images (blocks 2 and 6).
- Brutalist Web Design: style only to solve problems, not to decorate (block 10.1).
- 0. Principles and scope
- 1. Canonical document order
- 2. Header and logo
- 3. Navigation
- 4. Content
- 5. Links
- 6. Images and multimedia
- 7. Tables
- 8. Forms and interaction
- 9. Dependencies
- 10. Optional graphic layer
- A real example
- Final notes
- Sources
This work is under a Attribution-NonCommercial-NoDerivatives 4.0 International license.
Help me keep writing
Every coffee gives me a push toward the next article.
Sure, it's on me!
Comments
There are no comments yet.