Using CSS without getting in the way of accessibility
CSS can make a page easier to use, but it can also quietly remove accessibility that the browser provided for free. Tiny text, low contrast, missing focus indicators, and layouts that break at 200% zoom are all styling decisions.
The useful goal is not a separate “accessible version”. It is a design that still works when people read, navigate, and configure their devices differently from you.
Contrast needs more than a nice palette
Text must remain readable against its background. Check the actual colour pairs, including muted text, placeholders, disabled controls, and text placed over images. A dark background does not automatically create good contrast, and text-shadow is not a reliable fix for a poor combination.
Colour should not be the only signal either. Links inside body text are a common example: an underline gives them a visual distinction even when someone cannot tell the colours apart.
a {
color: #0645ad;
text-decoration: underline;
}
a:hover {
text-decoration-thickness: 0.15em;
}
Hover styles are useful, but anything available on hover also needs to work with a keyboard and on a touch screen.
Do not erase focus
Keyboard users need to see which control currently has focus. Removing outlines with outline: none may make a screenshot cleaner, but it makes the live page much harder to navigate.
Style the focus indicator instead:
:focus-visible {
outline: 3px solid #f5a623;
outline-offset: 3px;
}
The indicator should have enough contrast against whatever sits behind it. Test the whole page with the Tab key; a perfectly styled indicator does not help if a menu cannot be opened or focus disappears behind a sticky header.
Avoid using positive tabindex values to repair the visual order. It is usually better to keep the DOM order logical and make the layout follow it.
Typography has to survive user settings
Readable type is more than choosing a font. Use a comfortable default size, enough line height, and lines that do not stretch across the entire screen.
body {
font-size: 1rem;
line-height: 1.5;
}
main {
max-width: 70ch;
}
Relative units such as rem make it easier for text to respond to the reader’s settings. Also check the page at 200% zoom. Content should reflow without requiring horizontal scrolling for ordinary text.
Be careful with fixed heights. They often clip text as soon as a heading wraps or someone increases the font size.
Respect motion and colour preferences
Animation can cause discomfort or make a page difficult to follow. The prefers-reduced-motion media query lets you offer a calmer version:
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
scroll-behavior: auto;
transition-duration: 0.01ms;
animation-duration: 0.01ms;
animation-iteration-count: 1;
}
}
That broad rule is a useful safety net, though a considered component-by-component version is better when motion communicates state. Remove decorative movement while preserving information.
prefers-color-scheme can provide light and dark themes, but both still need good contrast. Dark mode is a preference, not an accessibility guarantee.
CSS and ARIA have different jobs
ARIA describes roles, names, properties, and states to assistive technology. CSS can select an ARIA attribute to reflect a state visually:
button[aria-expanded="true"] .icon {
transform: rotate(180deg);
}
But CSS does not make the ARIA true. JavaScript must update aria-expanded when the control changes, and the HTML must still use the right native element. Prefer a real <button> to a clickable <div> with several attributes trying to imitate one.
Test the design, not just the stylesheet
Automated tools can catch contrast failures and some missing attributes. They cannot tell you whether the page makes sense or whether every task can be completed.
I would at least test keyboard navigation, zoom and text resizing, light and dark modes, reduced motion, and one screen reader. User testing with disabled people will reveal problems that a checklist cannot.
Accessible CSS is often ordinary CSS used with a little restraint. Preserve browser behaviour, make each state visible, and let the page adapt. That tends to improve the design for everyone, which is a nicer result than maintaining a special mode nobody remembers to test.