Distraction-Free Reading Mode Toggle — HTML CSS JS Snippet

Distraction-Free Reading Mode Toggle · Layouts · Plain HTML, CSS & JS · Live preview

Share & Support

What's included

Features

Animated CSS Grid: grid-template-columns interpolates the sidebar track from 260px to 0px on toggle
Synchronized transitions: grid columns, gap, max-width, font-size, and background all animate over the same 0.4s window
Optimal reading measure: max-width: 70ch clamps line length to the 65-75 character range typography research favors
Sidebar fade-and-collapse: opacity plus pointer-events: none removes interactivity before the track fully collapses
Warm background shift: page background cross-fades from white to #faf6ee to reduce eye strain in reading mode
Typography scale-up: font-size 16px to 18px and line-height 1.65 to 1.9 for a more comfortable long-form read
localStorage persistence: reading-mode preference is remembered and reapplied automatically on every visit
Accessible toggle: aria-pressed reflects state and the button label swaps between "Reading Mode" and "Normal View"

About this UI Snippet

Distraction-Free Reading Mode Toggle — Animated Grid Layout Switching Between Normal and Reading Views

Screenshot of the Distraction-Free Reading Mode Toggle snippet rendered live

Every long-form content page fights the same underlying tension: the business needs sidebars, promo blocks, and related-content rails to drive engagement and revenue, while the reader just wants to read. A reading mode toggle resolves that tension without forcing a permanent tradeoff — the promotional layout stays the default, but a single click hands control back to the reader whenever they actually want to focus. This snippet implements a complete, animated reading mode toggle: click the button in the header and the sidebar and promo block disappear, the text column narrows to an optimal reading measure, line-height and font-size increase slightly, and the page background shifts to a warmer off-white — all transitioning smoothly rather than snapping instantly.

Why the transition is animated, not instant

An abrupt layout jump-cut — sidebar vanishing and column width changing in a single frame — is genuinely disorienting. The eye has to re-locate where it was reading, and a sudden width change during that split second breaks the reader's flow far more than the mode change was meant to help it. This snippet instead applies transition: grid-template-columns 0.4s ease, gap 0.4s ease, max-width 0.4s ease on the .layout-grid container, so the CSS Grid engine animates the sidebar's column track from 260px down to 0px and the gap from 40px to 0 continuously, while .article-col p transitions its own font-size and line-height in parallel. The background colour of .page-wrap cross-fades from white to a warm off-white (#faf6ee) over the same 0.4s window using a plain background transition, so every visual change lands together as one coherent motion rather than several uncoordinated snaps.

Why grid-template-columns is the right property to animate

CSS Grid track sizes are technically discrete values, but modern browsers interpolate grid-template-columns smoothly when both the before and after values are animatable lengths, which is exactly the technique this snippet relies on: the sidebar column goes from 260px to 0px rather than the sidebar simply being removed from the DOM or hidden with display: none mid-transition. Pairing that with opacity and pointer-events: none on .side-col lets the sidebar's content fade out visually at the same time its track collapses, so by the time the column reaches zero width there is nothing left partially visible to look broken or clipped.

The optimal reading measure: why 65 to 75 characters per line

Typography research consistently converges on roughly 65 to 75 characters per line — commonly written as 65-75ch in CSS — as the width at which the eye can track from the end of one line to the start of the next without losing its place, especially over long stretches of reading. This snippet sets max-width: 70ch on paragraph text specifically inside .layout-grid.reading, alongside a larger font-size: 18px (up from 16px) and a roomier line-height: 1.9 (up from 1.65). None of these values apply in the normal view, where the wider two-column layout is expected to carry more visual density.

Why this matters for 2026 calm UI design

Calm UI — interfaces that reduce cognitive load rather than compete for attention — has become a defining expectation for any product built around sustained reading or focus, not just a niche accessibility feature. Giving readers an explicit, persistent, one-click way to strip a page down to just its content respects their attention without forcing the publisher to give up the promotional layout as a permanent default. Because the toggle state is saved to localStorage under the key reading-mode, a reader who prefers the distraction-free view gets it automatically on every subsequent article, and the animated transition keeps the switch between the two states feeling considered rather than abrupt.

Build with AI

Build, Understand, Optimize, and Extend It With AI

Paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to explain exactly how grid-template-columns, gap, and the paragraph font-size/line-height transitions are kept in sync on the same 0.4s duration so the whole layout change reads as one motion instead of several separate snaps. It's a good prompt to also ask the assistant to add an aria-hidden toggle on the sidebar for screen reader correctness, since opacity and pointer-events alone hide it visually and from interaction but not from assistive technology. You could additionally ask it to wire prefers-reduced-motion so the transition duration drops to near-zero for users who have that OS-level preference set, or to extract the reading-measure and line-height values into CSS custom properties so a design system can tune them without touching the transition logic itself.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build a distraction-free reading mode toggle in plain HTML, CSS, and JavaScript for an article page that normally shows a sidebar with widgets and a promotional block next to the article text.

Requirements:
- A toggle button in the page header that switches between a "normal" view (sidebar visible, full-width two-column CSS Grid layout, tighter line-height) and a "reading" view (sidebar hidden, content column narrowed, looser line-height, slightly larger font-size).
- The content column's max-width in reading mode must clamp to roughly 65-75 characters per line (for example max-width: 70ch), which is the range typography research treats as the optimal reading measure.
- The transition between the two states must be animated, not an instant jump-cut — animate the CSS Grid column track (grid-template-columns), the gap, the paragraph font-size and line-height, and the page background color together over the same duration and easing so the whole change reads as one coordinated motion.
- The sidebar must both visually fade out (opacity) and stop being interactive (pointer-events: none) as its grid track collapses toward zero width, rather than disappearing abruptly mid-animation.
- The page background should shift to a slightly warmer, lower-contrast tone in reading mode to reduce eye strain, cross-fading rather than switching instantly.
- The toggle button must expose its state via aria-pressed and update its visible label (for example "Reading Mode" vs "Normal View") so the current state is clear to both sighted and assistive-technology users.
- Persist the chosen mode to localStorage so it is automatically reapplied the next time the page loads.

Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.

Step by step

How to Use

  1. 1
    Click "Reading Mode" in the headerThe button toggles between "Reading Mode" and "Normal View" labels. Watch the sidebar (trending widget and subscribe promo) fade and collapse away while the article column narrows and re-centers, all animating together rather than jumping instantly.
  2. 2
    Notice the typography changesIn reading mode, body paragraphs grow from 16px to 18px, line-height increases from 1.65 to 1.9, and the max-width clamps to 70ch — the CSS Grid track and font transitions are wired to fire over the same 0.4s window in the CSS panel so nothing lands out of sync.
  3. 3
    Notice the warmer backgroundThe .page-wrap background cross-fades from white to a warm off-white (#faf6ee) when reading mode is active, a subtle cue commonly used by e-readers and reading apps to reduce eye strain during long sessions compared to stark white.
  4. 4
    Reload to see the persisted preferenceToggle reading mode on, then reload the demo. setReadingMode() reads localStorage.getItem("reading-mode") on load and applies the saved state immediately, so a reader's preference carries over to their next article rather than resetting every visit.
  5. 5
    Inspect the animated grid-template-columnsIn the CSS panel, .layout-grid uses grid-template-columns: minmax(0, 1fr) 260px normally, switching to minmax(0, 1fr) 0px in .reading. Because both values are transitionable lengths, the browser animates the sidebar track width smoothly instead of it vanishing in one frame.
  6. 6
    Export and wire to real article contentClick HTML or JSX to export, then replace the sample paragraphs with your CMS-rendered article body inside .article-col, and your real sidebar widgets inside .side-col. Keep the aria-pressed attribute in sync with the JS toggle so assistive technology announces the current state correctly.

Real-world uses

Common Use Cases

News and publisher sites with sidebar-heavy article templates
Publishers need trending widgets, related articles, and subscription promos to drive engagement and revenue, but these same elements are exactly what a focused reader wants to escape. A reading mode toggle lets both goals coexist: the promotional layout stays the default for casual browsing, while a single click gives readers who are actually committing to an article the distraction-free version they want.
Documentation and knowledge-base long-form guides
Technical documentation with lengthy conceptual guides benefits from the same narrowing-and-widening treatment as editorial content — a developer working through a long architecture explainer wants the same 65-75ch measure and increased line-height as a magazine reader, without permanently redesigning the doc site's default three-column layout.
Newsletter and blog platforms competing with dedicated reader apps
Standalone reader apps like Pocket and Reader View exist specifically because publisher pages are often too busy to read comfortably. Building an equivalent reading mode directly into the page removes the need for readers to export content to a third-party app, keeping them (and your analytics, and your subscribe prompts) on your own site.
Editorial design systems wanting a calm, considered reading state
Design systems oriented around calm UI can expose a shared reading-mode class and CSS custom properties for the measure, line-height, and background shift so every article template — news, blog, documentation — gets a consistent distraction-free state without reimplementing the toggle from scratch each time, similar in spirit to how the Text Size Adjuster exposes one shared scaling variable.
Session-based focus mode for research and study tools
Research tools, study apps, and PDF-adjacent web readers can use the same animated grid-collapse pattern to let users temporarily hide annotation panels, citation sidebars, or tool palettes while reading a source in full, then bring them back with one click once they need to reference or act on the material again.
Teaching animatable CSS Grid tracks and coordinated multi-property transitions
This snippet is a clean reference for animating grid-template-columns itself rather than just opacity or transform, plus the discipline of keeping several unrelated CSS transitions (grid track, font-size, line-height, background) on the same duration and easing so a multi-property layout change reads as one coherent motion instead of several uncoordinated ones.

Got questions?

Frequently Asked Questions

Yes, in all modern browsers, as long as both the starting and ending values are compatible lengths — this snippet transitions between minmax(0, 1fr) 260px and minmax(0, 1fr) 0px, both of which are interpolatable. Browsers will smoothly animate the track size between the two rather than snapping. Grid layouts using keyword values like auto or fr-only tracks on both sides of the transition may not interpolate as smoothly, so keeping at least one side expressed in a fixed unit like px is the safer approach for animation.

Typography and reading-comprehension research consistently finds that lines much shorter than about 45 characters force the eye to make too many line breaks per sentence, while lines longer than roughly 75-90 characters make it easy to lose the correct line when the eye returns to the left margin, especially at high reading speeds. The 65-75ch range, set here via max-width: 70ch, balances both failure modes and is the range used by most dedicated reading apps and typography-focused editorial sites.

A subtle warm shift (this snippet uses #faf6ee) is a common and well-tested choice because pure white at high brightness can cause eye strain during extended reading, and a slightly warmer, lower-contrast background reduces that without sacrificing legibility. It is optional, though — some users and brands prefer to keep white and rely on the narrower measure and larger type alone; the background transition can simply be removed if it does not fit your product's visual identity.

This snippet already does that: setReadingMode() is called with the value read from localStorage.getItem("reading-mode") on every load, so once a user toggles reading mode on, it is applied automatically on their next visit without them needing to click the button again. For a server-rendered app, you can go further and read the same preference server-side from a cookie to avoid any flash of the normal layout before JavaScript runs.

Used correctly it does not: opacity: 0 combined with pointer-events: none removes the sidebar from click and hover interaction and visually hides it, but the elements technically remain in the DOM and tab order unless you also remove them or set aria-hidden. For a fully robust implementation, add aria-hidden="true" to the sidebar when reading mode is active (and remove it when reading mode is off) so screen reader users do not encounter now-irrelevant widgets while tabbing through the narrowed reading view.