Read Markdown in dark mode or light mode
Bobby Huang ·
Check your Mac's setting with defaults read -g AppleInterfaceStyle, which prints Dark in dark mode and an error in light mode. In a terminal, color the headings with grep --color=always -E '^#.*|$' notes.md | less -R so they stand out from the body text. For a page, export with pandoc and a small stylesheet that sets color-scheme to light dark and swaps colors inside a prefers-color-scheme dark block. The page then follows the light or dark preference the browser reports, usually your system setting, with no switch to flip.
Key takeaways
- A page that ignores your light or dark setting is hard on the eyes, so let the page follow the system instead of picking one look.
- On a Mac, defaults read -g AppleInterfaceStyle prints Dark in dark mode and exits with an error in light mode, because the setting is absent.
- In a terminal, grep with --color=always and less -R keeps every line and paints the headings so they stand out from the body text.
- A pandoc page with color-scheme light dark and a prefers-color-scheme dark block switches colors on its own when the browser's light or dark preference changes, which usually follows the system.
- Sashmark is in development and not released; light and dark, following the system, is planned for v1.
You open the plan your agent wrote at eleven at night, and the page glares white while everything else on your screen is dark. Or you're in a bright office with your system set to light, and a dark page full of gray text turns into a squint. Neither is a disaster. Both wear on your eyes when you read a lot of agent output.
The fix is simple: don't pick a look for the file. Let it follow the light or dark setting your system already has. This page covers Markdown dark mode and light mode in two places, a terminal and an exported page, with commands you can copy.
If you still need the basics of opening a file or paging through it with less, start with how to open and read a Markdown file. For when to read the formatted page and when to read the raw text, see rendered vs raw agent Markdown.
Why Markdown dark mode matters
A page that ignores your setting fights the rest of your screen. Switching between a dark screen and a bright page is tiring over a long session.
So the goal is not "always dark" or "always light." The goal is a file that matches whatever your system is set to right now, and switches when you do.
The examples below use this small agent-written file, saved as notes.md:
# Release plan
Owner: Jane Doe
## Steps
- [x] Draft the notes
- [ ] Review the notes
## Risks
The agent may rewrite this file.
If any of the syntax is new to you, the Markdown syntax guide covers it.
Check what your Mac is set to
Before you test anything, know which mode you're in. On a Mac, one command tells you:
defaults read -g AppleInterfaceStyle
In dark mode it prints one word and exits with code 0:
Dark
In light mode the setting isn't stored at all, so there is nothing to read. When a key is absent, the command prints an error and exits with code 1. Here is the shape of that error, captured with a made-up key name. In light mode, expect the same line with AppleInterfaceStyle where the key name is:
Error: Could not find key 'NoSuchKeyDoe' in domain 'kCFPreferencesAnyApplication'.
So "Dark" means dark mode, and that error means light mode. Linux desktops have their own appearance setting.
Read Markdown in a terminal with colored headings
Raw Markdown in a terminal is one block of same-colored text. On a dark background the headings blend in; on a light one they do too. Coloring the heading lines gives your eye something to land on in either mode.
Run this from the folder that holds the file:
grep --color=always -E '^#.*|$' notes.md | less -RScroll with the arrow keys or the space bar, and press q to quit.
Here is what each part does:
^#.*matches a heading line, from the#at the start to the end of the line.|$also matches the end of every line. That match is empty, so nothing gets colored, but it means every line is kept. Without it, grep would show only the headings.--color=alwaysadds the color codes even though the output goes into a pipe. Without it, grep sends no color codes into a pipe.less -Rshows those color codes as color. Without-R, you would see the raw codes as text.
The codes really are there. Piping the same command into cat -v instead of less prints them as plain characters:
^[[01;31m^[[K# Release plan^[[m^[[K
Owner: Jane Doe
^[[01;31m^[[K## Steps^[[m^[[K
- [x] Draft the notes
- [ ] Review the notes
^[[01;31m^[[K## Risks^[[m^[[K
The agent may rewrite this file.
Each heading is wrapped in a start code and a stop code; every other line passes through untouched. These runs used the grep that comes with macOS, at /usr/bin/grep. If grep in your shell points at a different tool, type /usr/bin/grep instead. Other greps take the same flags.
The color comes from your terminal's own palette.
Export a page that follows light or dark
When you want a formatted page instead of raw text, pandoc (a document converter) can turn the Markdown into HTML with a stylesheet attached. The stylesheet is where the light and dark behavior lives.
Save this as reading.css in the same folder as notes.md:
:root { color-scheme: light dark; --text: #1f1e1c; --page: #fbfaf7; --link: #1d4ed8; } @media (prefers-color-scheme: dark) { :root { --text: #e8e6e1; --page: #1f1e1c; --link: #93b4ff; } } body { color: var(--text); background: var(--page); max-width: 40rem; margin: 2rem auto; padding: 0 1rem; font: 1.05rem/1.6 system-ui, sans-serif; } a { color: var(--link); }Export the page:
pandoc notes.md -s --css reading.css --metadata title="Release plan" -o notes.htmlThe
-sflag makes a full standalone page, and--csslinks the stylesheet. The title is set because a standalone page needs one.Check that the page links the stylesheet:
grep -n 'reading.css' notes.htmlYou should see a line like this:
28: <link rel="stylesheet" href="reading.css" />The page links the file rather than copying it in, so keep reading.css next to notes.html.
Two parts of the stylesheet do the work:
color-scheme: light dark;tells the page it supports both modes.- The
@media (prefers-color-scheme: dark)block applies when the browser reports a dark preference, which usually comes from the system setting. It swaps the three colors: light text on a dark page, and a lighter link blue that still reads on the dark background. In light mode the block is skipped and the colors at the top apply.
In a headless browser set to dark, the page background came out rgb(31, 30, 28); set to light, rgb(251, 250, 247).
Habits that keep both modes readable
- Keep contrast high in both modes. Dark gray text on a dark page, or pale text on a light one, is just as tiring as a glaring page. The colors above pair a near-black with a near-white each way.
- Test the page in both modes once. Switch your system setting, reload the page, and read a paragraph. If one mode looks off, fix the colors in that block and move on. You don't need to check every file after that.
Where Sashmark fits
Everything above uses free tools, though pandoc is a separate install. A good reader should follow your system's light or dark setting on its own, without a stylesheet or a pipe to set up. Sashmark is being built for this; light and dark, following the system, is planned for v1, and the roadmap shows where it stands. Sashmark is a Markdown reader and editor for people whose AI agents write Markdown, being built for Mac, Windows and Linux, and it has no AI features of its own. See the planned features for the rest.
Sashmark is in development. See what it is at sashmark.com.
Questions
- Why does defaults read print an error in light mode?
- In light mode the AppleInterfaceStyle setting is not stored at all, so there is nothing to read. Expect a "Could not find key" error and exit code 1, the same as for any missing key. In dark mode it prints Dark and exits with code 0.
- Why do I need --color=always when I pipe grep into less?
- Without --color=always, grep sends no color codes into a pipe. The --color=always flag adds the codes even when the output goes into a pipe, and less -R shows them as color instead of raw characters.
- Do I have to change the stylesheet when I switch between light and dark?
- No. The color-scheme line and the prefers-color-scheme dark block let the page pick its colors from the browser's light or dark preference, usually your system setting, each time it loads. You set it up once and test it in both modes once.