cd /news/developer-tools/web-design-for-terminal-browsers · home topics developer-tools article
[ARTICLE · art-90488] src=en.andros.dev ↗ pub= topic=developer-tools verified=true sentiment=· neutral

Web Design for Terminal Browsers

A guide to web design for terminal browsers finds that JavaScript is absent in all five major text engines—w3m 0.5.6, lynx 2.9.3, links 2.30, elinks 0.20.0, and Emacs EWW—and CSS is largely ignored except for partial support in elinks, making `display:none` by class ineffective and `alt` text the primary image content. The author proposes 8 rules for terminal-friendly publishing, emphasizing DOM order and avoiding hidden content via CSS.

read10 min views1 publishedAug 10, 2026
Web Design for Terminal Browsers
Image: source

This is a purely-for-fun exercise: a guide to web design for terminal browsers. Starting from the text browsers people actually use, I am going to pull out a set of rules in case you ever decide to build a site meant to read and look its best in a terminal. It is not an alternative to Gemini, Gopher or a smallweb attempt, but a set of best practices so your site reads well in a terminal browser, and even so you can build Web Apps for the terminal.

Five engines, one test #

The first step is to install the five text engines people actually use and feed them the same test pages, isolating one feature at a time.

w3m(0.5.6): the most capable with tables, and it even draws images in terminals that allow it.** lynx**(2.9.3): the patriarch, the lowest common denominator since 1992.** links**(2.30): fast, with a little bit of CSS.** elinks**(0.20.0): the cousin with bigger ambitions, it even has an optional CSS engine.** EWW**: the Emacs one.

Now we look for the compatibility crossovers. You test HTML and CSS features and see how each engine interprets them.

The results:

Feature EWW w3m lynx links elinks
JavaScript No No No No No
<style> / <link> sheets
No No No No Partial
display:none inline
Hides Shows Shows Hides Shows
display:none by class
Shows Shows Shows Shows Shows
inline color
Yes (with contrast) Depends on the terminal Depends on the terminal Depends on the terminal Depends on the terminal
text-align
No No No No Yes
Data tables Yes Yes Yes (no borders) Yes Yes
colspan / rowspan
Yes Yes Flattens Yes Yes
Graphical images Yes In the terminal No No No
alt of a broken image
Yes Yes Yes Yes Yes
srcset
Yes (picks resolution) alt/src alt/src alt/src alt/src
data: URI in an image
Yes alt alt alt alt
GET/POST forms Yes Yes Yes Yes Yes
Collapsible <details>
No No No No No
Spacing of <article> , <section> ...
No No No No No
<base href>
Yes Yes Yes Yes Yes
<title> , <pre> , <hr> , lists
Yes Yes Yes Yes Yes

From this we draw some general conclusions:

JavaScript does not exist. In any of them. It is not slow or partial. There simply is no interpreter.CSS is almost a mirage. Stylesheets, whether<style>

or<link>

, are ignored in all of them except elinks, which applies a few things liketext-align

. Four out of five engines do not read your CSS. Design as if it were not there.If you hide something with a class (display:none

is a trap.class="hidden"

and.hidden{display:none}

in your sheet),all five engines show it. Every one. Because they do not read the sheet: do not hide anything important with CSS. If it should not be seen, do not put it in the HTML.Images are text. Only EWW (and w3m in some terminals) actually draws the image. In the rest, the imageisitsalt

attribute. All five fall back toalt

when the image is broken, and an image with noalt

leaves you a[hero]

with the file name, or nothing at all.alt

is not accessibility for others, it is your content.None of the five make it interactive. The summary and the body always show, one after the other.<details>

does not fold.HTML5 semantic tags are invisible.article

,section

,nav

,header

,footer

,main

,aside

: they are transparent containers. They do not add a single line break. Their value is semantic, not visual.

With that, we can lay down a few design lines and best practices.

8 rules for publishing to the terminal #

1. DOM order rules

There is no float

, no flex

, no grid

, no order

. Whatever you put first in the HTML comes first on screen. So place the content right after opening the <body>

and send the long navigation and the footer to the end. A reader who opens your article does not want to tab through thirty menu links before reaching the first sentence.

2. Mark structure with tags, not styles

Real headings <h1>

..<h6>

for the hierarchy, never a <div class="big-title">

. Lists with <ul>

/<ol>

, definitions with <dl>

. Quotes with <blockquote>

, which all of them indent. Code with <pre>

and <code>

. Each engine gives them its own treatment: use them for what they mean.

3. Your page must read with CSS turned off

This is the touchstone. If you disable CSS and your page becomes unreadable, it is not the terminal browser's problem, it is your HTML's problem. Spacing (margin

, padding

, line-height

) does not exist: the separation comes from paragraphs. Structure with real <p>

, not with loose <br>

.

4. Do not convey information with color alone

A "required field in red" or a "green = correct" evaporate. Inline color

is the most fragile thing in the table: it depends on the terminal and its configuration, and in many cases it does not even show. Always pair color with text or a symbol. An "Error:" in front, an asterisk, anything.

5. Tables for data only, never for layout

EWW and w3m draw a surprisingly good ASCII grid, colspan

and rowspan

included. But a layout table produces an absurd, unreadable grid. Watch the width: if the columns add up to more than the terminal's, the experience degrades. Fewer columns and short cells win.

6. Images with a descriptive alt

and srcset

alt

is what you see in four out of five engines. Make it a sentence, not an image1.png

. And if the image is pure decoration, give it an explicit alt=""

: that way the reader ignores it instead of reading you the file name. A missing alt

and an empty one are not the same thing. Offer srcset

with several resolutions, and the engine that can show images will pick the right one. And do not rely on an image to communicate anything critical, because in most engines they do not load at all.

7. Real forms

No JavaScript submissions. A <form>

with its action

and its method

(GET or POST), and an <input type="submit">

or a <button>

. Put a name

on every field: the engines collect by name

, and a field without one is lost. Associate a <label>

with each one.

8. Headers that do count

<title>

always, descriptive: lynx and links center it at the top, and all of them use it to identify the page. <meta charset>

in UTF-8 as an encoding fallback. <base>

if you use relative links, which all of them respect. And serve over HTTPS, since several engines flag the certificate status.

TerminalSpeed Insights #

A guide you cannot run is a list of good intentions. So I wrote a prototype. It is a Python script that reads an HTML file, or a URL, and gives you back a readability score with the specific warnings. The number is a heuristic, not a science. I hand out the points by eye, an error weighs more than a warning and that is that. What really matters is the list of warnings, not the scoreboard.

You can download it from its repository, TerminalSpeed Insights, and run it against any page:

python3 wwwlint.py https://your-site.dev/

Running it over a few popular sites, the ones leaning more on content than design, I get some numbers:

Site Score
andros.dev (this blog) 100
text.npr.org (NPR's text-only version) 100
motherfuckingwebsite.com 100
emacswiki.org 94
suckless.org 94
gnu.org 88
man pages on man7.org 88
Wikipedia (an article) 46
Hacker News 55

At the top are the wikis, the docs, the text sites and the ones that fly the minimalism flag. At the bottom, curiously, two of the sites most loved by people who read in the terminal. It is no coincidence: the ones that score high serve the content first and lean on the tags, not on CSS. EmacsWiki, for instance, is almost plain HTML, and that is why it reads on anything that can show text.

Still, these are numbers not every browser shares. Open Hacker News in w3m and you will see the front page perfectly readable, with its numbered list of headlines, despite that 55. w3m draws tables so well that it survives. The validator is not wrong to penalize it, it flags real friction, but friction is not always a death sentence. Take the score as a guide, not a verdict: a 100 almost guarantees it reads well, a low number tells you where to look.

Not just documents: a Terminal Web App #

So far I have talked about documents: articles, cards, docs pages. We still have to squeeze the forms: GET and POST work in all five engines. And a form that works is, no more and no less, an application.

Let me show you with a coffee shop:

<form action="/order" method="post">
  <p><label>Your name <input type="text" name="name"></label></p>
  <p><label>Quantity <input type="number" name="qty" 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>

And this is how it looks in EWW, the Emacs browser. The fields are edited with the keyboard; here I have already filled in the name, the quantity and checked "No milk":

You hit submit and the <form>

does a POST. The server responds with a redirect (the good old Post/Redirect/Get pattern) and the browser paints the confirmation, all without leaving the keyboard or touching the mouse:

Look at the detail: heading in bold, the link colored, the quantity and the no-milk option collected correctly. It is a stateful app, interactive, with no JavaScript and without a single kilobyte of framework. And yes, it scores 100 with the validator.

It is a real application: it lives in the text browser, but it looks just as good in Chrome or Firefox, because underneath there is only HTML. You get a terminal interface without touching ncurses

or any TUI library. Your toolkit is HTML, your renderer is the browser and your logic lives on the server. The same app, a language you already know, and it works everywhere.

Conclusion #

It has been a fun investigation. Almost nobody designs their sites for the terminal, it is a minority and, even so, it is an audience that exists. And there is no shortage of reasons: these are visitors who want accessibility or speed, who are on low resolutions or who work with pipes. More than once I have found myself doing quick searches in EWW, or reading an article there for the visual comfort.

You can take it as a curious article or as another approach to web design. I, at least, will start looking at my pages with different eyes.

I hope you enjoyed this other point of view on web design.

Five engines, one test - 8 rules for publishing to the terminal - 1. DOM order rules - 2. Mark structure with tags, not styles - 3. Your page must read with CSS turned off - 4. Do not convey information with color alone - 5. Tables for data only, never for layout - 6. Images with a descriptive alt and srcset - 7. Real forms - 8. Headers that do count - TerminalSpeed Insights - Not just documents: a Terminal Web App - Conclusion

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.

Comments #

There are no comments yet.

── more in #developer-tools 4 stories · sorted by recency
── more on @w3m 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/web-design-for-termi…] indexed:0 read:10min 2026-08-10 ·