Print Styles & Dark Mode

Difficulty: Intermediate

Question

How do you implement print styles and dark mode in CSS?

Answer

Print styles optimize pages for printing. Dark mode adapts to user's OS theme preference.

Print styles: - Use @media print { } to add print-specific rules - Hide navigation, footers, ads - Use black text on white background - Set page margins with @page - Force background printing with print-color-adjust

Dark mode: - prefers-color-scheme: dark media query (OS preference) - Class-based toggle (.dark) for manual control - CSS custom properties for theme values - color-scheme meta tag for native form styling

Code examples

Print Styles

@media print {
  /* Hide non-essential elements */
  nav, footer, .sidebar, .ads,
  .no-print, button {
    display: none !important;
  }

  /* Reset colors for print */
  body {
    color: black;
    background: white;
    font-size: 12pt;
    line-height: 1.5;
  }

  /* Show link URLs */
  a[href]::after {
    content: ' (' attr(href) ')';
    font-size: 0.8em;
    color: #666;
  }
  a[href^="#"]::after,
  a[href^="javascript:"]::after {
    content: ''; /* skip internal/JS links */
  }

  /* Page settings */
  @page {
    margin: 2cm;
    size: A4;
  }

  /* Avoid breaking inside elements */
  h2, h3, img, table {
    break-inside: avoid;
  }
  h2, h3 {
    break-after: avoid;
  }

  /* Force background printing */
  .badge {
    print-color-adjust: exact;
    -webkit-print-color-adjust: exact;
  }
}

Print styles remove UI elements, optimize for paper, and show link URLs. break-inside: avoid prevents awkward page breaks in the middle of elements.

Dark Mode with CSS Variables

/* Define theme tokens */
:root {
  color-scheme: light dark;
  /* Tells browser to style native controls */

  --bg: #ffffff;
  --bg-surface: #f9fafb;
  --text: #111827;
  --text-muted: #6b7280;
  --border: #e5e7eb;
  --shadow: 0 1px 3px rgb(0 0 0 / 0.1);
}

/* OS preference: auto dark mode */
@media (prefers-color-scheme: dark) {
  :root {
    --bg: #0f172a;
    --bg-surface: #1e293b;
    --text: #f1f5f9;
    --text-muted: #94a3b8;
    --border: #334155;
    --shadow: 0 1px 3px rgb(0 0 0 / 0.4);
  }
}

/* Manual toggle: class on html element */
html.dark {
  --bg: #0f172a;
  --bg-surface: #1e293b;
  --text: #f1f5f9;
  --text-muted: #94a3b8;
  --border: #334155;
  --shadow: 0 1px 3px rgb(0 0 0 / 0.4);
}

/* Apply tokens everywhere */
body {
  background: var(--bg);
  color: var(--text);
}
.card {
  background: var(--bg-surface);
  border: 1px solid var(--border);
}

CSS variables make dark mode trivial - change the variable values and every component updates. color-scheme tells the browser to style checkboxes, scrollbars, etc.

Dark Mode JavaScript Toggle

<!-- Meta tag for native control styling -->
<meta name="color-scheme" content="light dark" />

<script>
// Check stored preference, then OS preference
function getTheme() {
  const stored = localStorage.getItem('theme');
  if (stored) return stored;
  return window.matchMedia(
    '(prefers-color-scheme: dark)'
  ).matches ? 'dark' : 'light';
}

// Apply theme
function setTheme(theme) {
  document.documentElement.classList
    .toggle('dark', theme === 'dark');
  localStorage.setItem('theme', theme);
}

// Initialize
setTheme(getTheme());

// Toggle button
document.getElementById('themeToggle')
  .addEventListener('click', () => {
    const current = document.documentElement
      .classList.contains('dark') ? 'light' : 'dark';
    setTheme(current);
  });

// Listen for OS changes
window.matchMedia('(prefers-color-scheme: dark)')
  .addEventListener('change', (e) => {
    if (!localStorage.getItem('theme')) {
      setTheme(e.matches ? 'dark' : 'light');
    }
  });
</script>

<style>
/* Smooth theme transition */
html {
  transition: background 0.3s ease, color 0.3s ease;
}
</style>

The three-tier approach: 1) check localStorage for user preference, 2) fall back to OS preference, 3) default to light. Listen for OS changes too.

Key points

Concepts covered

Print Styles, Dark Mode, prefers-color-scheme, Color Scheme, Accessibility