How to check contrast, legibility, and focus states for accessible dark mode

Dark mode can look sleek, but it often hides accessibility problems that frustrate real users. How do you ensure colours, type, and keyboard focus work as well at low luminance as they do in light themes?

This guide walks through defining colour rules, measuring contrast, optimising typography, designing clear focus states, and testing in practical scenarios to surface those issues. Follow along to learn concise checks, useful tools, and examples that let you validate accessible dark mode across devices and assistive technologies.

Define dark mode colour rules

Start by defining a small set of semantic colour tokens for roles such as background, surface, primary text, secondary text, interactive, disabled, and focus indicator, and attach explicit contrast targets based on WCAG 2.1: 4.5:1 for normal text, 3:1 for large text and non-text UI components, and 7:1 where you want enhanced legibility. Make the tokens the single source of truth so changes propagate predictably between light and dark modes, and include state-specific tokens for hover, active, pressed, and disabled rather than relying on ad hoc overrides. Specify focus indicator tokens with a minimum 3:1 contrast against both the element and the adjacent background, and document minimum visible thickness and offset so the indicator survives zoom, scaling, and high pixel density. Combine automated contrast checks with manual inspections, including greyscale rendering, keyboard-only flows, and common colour-blindness simulations, and include example pass and fail screenshots or code snippets so teams can reproduce and validate results.

When deriving dark variants, prioritise changes in perceptual luminance over hue: convert light-mode colours to a perceptual colour space, reduce luminance to create dark counterparts, then verify contrast numerically. Run a greyscale test to ensure typographic and interactive hierarchy survives without colour, and avoid absolute black or pure white for backgrounds and text because near-black and near-white choices often reduce halation while still meeting contrast ratios. Test focus visibility with keyboard navigation across different background tones, and document the trade-offs by comparing measured contrast values and subjective legibility in realistic scenes so designers and engineers can make informed decisions.Request an accessibility-focused UX audit to improve contrast and hierarchy

Measure and meet contrast standards

Start by targeting the WCAG thresholds: 4.5:1 for normal text, 3:1 for large text and user interface components, and 7:1 for AAA large-text or higher assurance. Calculate contrast as (L1 + 0.05) / (L2 + 0.05), where L is relative luminance computed from sRGB by converting each 8-bit channel to 0–1, linearising with the sRGB gamma rule, then combining as L = 0.2126R + 0.7152G + 0.0722B. For a worked example, white on black gives Lforeground = 1 and Lbackground = 0, so the ratio is (1 + 0.05) / (0 + 0.05) = 21:1, a straightforward result to reproduce. Always test colours after compositing by alpha blending in linear space using result = alpha * foreground + (1 – alpha) * background per channel, because semi-transparent white over a dark base can fall below target and you can recover contrast by reducing translucency or shifting hue.

Validate focus and interactive states separately from static text by ensuring focus rings, keyboard indicators, and pressed or hover fills meet at least 3:1 against the immediate adjacent area, and measure the outline, the fill, and any overlapped region. Combine automated checks of theme tokens and UI components in your build with manual spot checks on representative screens, real devices, varied ambient lighting, zoom and magnifier simulations, and colour-blindness tools to catch cases automated tools miss. Improve legibility holistically by increasing size, weight, line-height, or letter spacing where contrast is marginal, and prefer high-contrast semantic tokens, because thin strokes, low-opacity text, and text placed on textured or photographic backdrops often fail even when numeric ratios appear acceptable.

Optimise typography for legibility

Set clear contrast targets and verify them both programmatically and visually, aiming for WCAG ratios of 4.5:1 for normal text, 3:1 for large text and UI components, and at least 3:1 for graphical objects. Run automated contrast checks, then inspect samples at several display brightness levels and on different screens to catch failures that tools miss. Avoid pure black and pure white by choosing slightly off-black backgrounds and near-white foregrounds to reduce halation and perceived glare, and prefer combinations that differ in luminance and hue rather than luminance alone.

Optimise typography for dark backgrounds by choosing faces with open counters and generous x-heights, using a slightly heavier weight for the same point size, and modestly increasing body size, tracking, and line-height to reduce crowding and improve scanning. Design focus and interactive states that remain visible in low-luminance contexts by avoiding reliance on subtle shadows or inner glows, and instead using high-contrast outlines or glows that meet contrast thresholds with both the element and the background. Validate these choices with real conditions and users: simulate lower vision and glare, run brief reading-speed or comprehension checks for long-form text, and combine automated reports with manual review to surface artefacts that automated tools cannot detect.

  • Verify contrast ratios programmatically and visually, aiming for WCAG targets of 4.5:1 for normal text, 3:1 for large text and UI components, and at least 3:1 for graphical objects; run automated contrast analysis across text sizes and component states, then inspect representative samples on several displays and brightness settings to surface failures tools miss.
  • Avoid pure black and pure white by choosing slightly off‑black backgrounds and near‑white foregrounds that differ in both luminance and hue to reduce halation and perceived glare; measure relative luminance, confirm colour differences for outlines or glows, and prefer combinations that pass contrast thresholds rather than relying on luminance alone.
  • Optimise type for low‑luminance contexts by selecting faces with open counters and generous x‑heights, using a slightly heavier weight for the same point size, and modestly increasing body size, tracking, and line height; make focus and interactive states visible without subtle shadows by using high‑contrast outlines or glows that meet contrast requirements with both the element and the background.
  • Validate with real conditions and users: simulate lower vision and glare, run brief reading‑speed or comprehension checks on representative content, test across device types and brightness levels, combine automated reports with manual QA, and document failure cases and fixes so teams can reproduce and prevent regressions.

Design clear focus states

Set measurable contrast targets for focus indicators and test each colour pair against both the component fill and the page background, aiming for a minimum 3:1 contrast ratio and verifying results with a contrast checker while logging any failing pairs for replacement in dark mode. Add at least two non-colour cues so users with colour vision deficiencies or low vision can find controls, for example a strong outline or box shadow combined with a shape change, thicker border, icon, or subtle scale shift, and keep any motion brief while honouring reduced motion preferences. Do not remove the browser focus without a visible alternative; audit custom components, SVG controls, and form elements, ensure focus appears when tabbing, and prevent visual clipping on rounded elements by using outline-offset or an external box shadow.

Test focus behaviour under realistic conditions: keyboard-only navigation, screen magnification, high contrast system modes, and zoom at larger scales to reveal omissions or clipping. Verify focus order is logical, that focus does not get lost inside modals, and that indicators remain visible when elements change state, such as hover to active. Prefer solid outlines or high-contrast shadows on dark backgrounds, set a visible thickness of around 2 pixels or more, ensure interactive targets meet recommended touch sizes, and use short transitions for clarity without delay. Keep a small, documented palette of accessible focus colours and bake these checks into audits or automated tests so regressions in dark mode are easy to find and fix.

Execute practical testing and validation

Run contrast measurements on every foreground and background pair, extract hex values, compute relative luminance, then calculate contrast as (L1 + 0.05) divided by (L2 + 0.05). Target a ratio of at least 4.5:1 for normal text, 3:1 for large text, and 7:1 for enhanced readability. Record failing pairs with screenshots and numeric ratios so remediation decisions are evidence based.

Simulate dark mode and forced inversion to catch visual breakage by toggling the site stylesheet with the prefers-colour-scheme media query and emulating system-level inversion, which often reveals inverted images, washed-out icons, or text rendered on semi-transparent tints. For images that contain text or logos, provide alternative assets or use SVGs that inherit the foreground colour to keep legibility consistent in dark contexts. Verify focus states and keyboard navigation by tabbing through interactive elements, ensuring indicators remain visible at browser zoom, have clear contrast with the background, and change more than one property, such as outline plus a subtle background, so users perceive focus in greyscale or high contrast settings. Combine automated audits with manual checks and user feedback, prioritise issues by impact using numeric evidence, and iterate until fixes are verifiable across devices, input methods, and viewing conditions.