Web Development /CSS — Styling Modern Websites / Lesson
Web Development

CSS Accessibility, Focus States and Inclusive Design

📖

Lesson Content

Introduction to CSS Accessibility

Good web development is not only about creating attractive interfaces. A professional website should also be usable by as many people as possible.

Web accessibility means designing and developing websites so that people with different abilities, devices and interaction methods can use them effectively.

CSS plays an important role in accessibility because it controls typography, spacing, color, visibility, focus indicators, animations, layout and responsive behavior.

Why CSS Accessibility Matters

Users may interact with websites using:

  • A mouse
  • A keyboard
  • A touchscreen
  • Screen readers
  • Browser zoom
  • Alternative input devices

A CSS design that works well for a mouse user may create problems for someone navigating entirely with a keyboard.

Accessible CSS attempts to ensure that visual presentation does not prevent people from using the content and functionality of a website.

Color Contrast

Text should have sufficient contrast against its background.

For example, light gray text on a white background can be difficult to read.

.description {
    color: #777;
    background: #fff;
}

A stronger contrast can improve readability.

.description {
    color: #334155;
    background: #fff;
}

Color should not be the only way important information is communicated.

Do Not Rely Only on Color

Consider a form that uses only red text to indicate an error.

.error {
    color: red;
}

A better interface can combine color with text and an appropriate visual indicator.

.form-message--error {
    color: #b91c1c;
    border-left: 4px solid #b91c1c;
    padding: 12px;
}

The message itself should also explain what went wrong.

Focus States

Keyboard users need to know which element currently has focus.

Interactive elements such as links and buttons should have a visible focus indicator.

a:focus {
    outline: 3px solid blue;
}

However, :focus-visible is often more useful because it allows developers to provide a focus indicator when keyboard-style focus indication is appropriate.

button:focus-visible,
a:focus-visible {
    outline: 3px solid #2563eb;
    outline-offset: 3px;
}

Why Removing Outline Can Be Dangerous

A common CSS pattern is:

button:focus {
    outline: none;
}

Removing the browser focus indicator without replacing it can make keyboard navigation difficult.

If the default outline is changed, provide another clearly visible focus style.

button:focus {
    outline: none;
}

button:focus-visible {
    outline: 3px solid #2563eb;
    outline-offset: 3px;
}

Keyboard Navigation

Try navigating a website using only the keyboard.

Press the Tab key to move through interactive elements.

A good interface should make it obvious where focus is located.

Users should be able to identify:

  • Which link is focused.
  • Which button is focused.
  • Which form field is focused.
  • Which interactive control will receive the next action.

Hover Is Not Focus

Hover effects are useful for mouse users, but keyboard users do not necessarily hover over elements.

This is not sufficient:

.button:hover {
    background: #1d4ed8;
}

A focus state should also be provided.

.button:hover {
    background: #1d4ed8;
}

.button:focus-visible {
    outline: 3px solid #60a5fa;
    outline-offset: 3px;
}

Readable Typography

Typography has a major effect on accessibility.

Important factors include:

  • Font size
  • Line height
  • Letter spacing
  • Line length
  • Contrast
  • Font weight

A comfortable line height improves readability.

body {
    line-height: 1.6;
}

Readable Line Length

Very long lines of text can make reading difficult.

The ch unit can help control text width.

.article {
    max-width: 70ch;
}

Responsive Text

Text should remain readable across different screen sizes.

h1 {
    font-size: clamp(2rem, 6vw, 4.5rem);
}

Fluid typography can help prevent headings from becoming too large or too small.

Do Not Disable Zoom

Users may need to zoom a webpage to make content easier to read.

Developers should avoid intentionally creating CSS or viewport settings that prevent normal browser zoom behavior.

Touch Targets

Interactive controls should have enough space to be comfortably selected on touch devices.

For example:

.button {
    min-height: 44px;
    padding: 10px 18px;
}

The exact dimensions depend on the design, but very small controls can be difficult to use on touchscreens.

Accessible Links

Links should remain visually identifiable.

a {
    color: #1d4ed8;
    text-decoration: underline;
}

a:hover {
    text-decoration-thickness: 2px;
}

a:focus-visible {
    outline: 3px solid #60a5fa;
    outline-offset: 3px;
}

Removing all visual distinction from links can make them harder to identify.

Accessible Buttons

Buttons should have clear visual states.

.button {
    border: 0;
    padding: 12px 20px;
    border-radius: 8px;
    background: #2563eb;
    color: white;
    cursor: pointer;
}

.button:hover {
    background: #1d4ed8;
}

.button:focus-visible {
    outline: 3px solid #60a5fa;
    outline-offset: 3px;
}

.button:disabled {
    opacity: 0.55;
    cursor: not-allowed;
}

Form Accessibility

Forms need clear focus states and readable labels.

input,
textarea,
select {
    width: 100%;
    padding: 12px;
    border: 1px solid #94a3b8;
    border-radius: 8px;
}

input:focus,
textarea:focus,
select:focus {
    border-color: #2563eb;
}

input:focus-visible,
textarea:focus-visible,
select:focus-visible {
    outline: 3px solid rgba(37, 99, 235, 0.25);
    outline-offset: 2px;
}

The HTML should also provide meaningful labels.

<label for="email">
    Email Address
</label>

<input
    id="email"
    name="email"
    type="email"
>

Hidden Content

CSS can visually hide content, but developers must understand the difference between hiding something visually and removing it from the accessibility experience.

For example:

.hidden {
    display: none;
}

This removes the element from normal rendering.

Another approach may visually hide content while keeping it available to assistive technologies, depending on the intended use.

.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

This technique can be useful for visually hidden labels or supporting text, but it should be used deliberately.

Reduced Motion

Animations can be helpful, but some users prefer reduced motion.

CSS provides the prefers-reduced-motion media feature.

@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms;
        animation-iteration-count: 1;
        transition-duration: 0.01ms;
        scroll-behavior: auto;
    }
}

This allows the interface to respect a user’s operating-system motion preference.

Accessible Animations

Animations should not make content difficult to understand or interact with.

For example:

.card {
    transition:
        transform 0.25s ease,
        box-shadow 0.25s ease;
}

.card:hover {
    transform: translateY(-4px);
}

The animation is relatively subtle and should also have a reduced-motion alternative.

Don’t Use CSS to Communicate Meaning Alone

CSS is responsible for presentation, while HTML provides structure and meaning.

Instead of relying on a CSS class alone:

<div class="error">
    Invalid email address
</div>

Use semantic HTML where appropriate:

<p class="form-message form-message--error">
    Please enter a valid email address.
</p>

The content communicates the problem while CSS controls the visual presentation.

Responsive Accessibility

Accessibility must be maintained across screen sizes.

A desktop layout may contain a horizontal navigation bar while a mobile layout uses a menu button.

Both versions should remain accessible to keyboard and assistive technology users.

Accessible Responsive Navigation

.navigation {
    display: flex;
    gap: 24px;
}

.menu-toggle {
    display: none;
}

@media (max-width: 700px) {
    .navigation {
        display: none;
    }

    .menu-toggle {
        display: inline-flex;
    }
}

.menu-toggle:focus-visible {
    outline: 3px solid #2563eb;
    outline-offset: 3px;
}

The JavaScript controlling the menu should also manage its state and accessibility attributes correctly.

Using :focus-visible

The :focus-visible pseudo-class is particularly useful for modern interfaces.

.nav-link:focus-visible {
    outline: 3px solid #2563eb;
    outline-offset: 4px;
}

It provides a clear focus indicator when keyboard-style navigation requires one.

Using :disabled

Disabled controls should have a clear visual state.

button:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

However, do not rely only on reduced opacity to communicate important information.

Using :checked

CSS can style controls based on their state.

input[type="checkbox"]:checked {
    accent-color: #2563eb;
}

State changes should remain understandable and usable.

Accessible Cards

A course card should not create unnecessary accessibility problems.

For example:

.course-card {
    border: 1px solid #e2e8f0;
    border-radius: 16px;
    padding: 24px;
}

.course-card__link {
    color: #1d4ed8;
}

.course-card__link:focus-visible {
    outline: 3px solid #60a5fa;
    outline-offset: 3px;
}

CSS and Screen Readers

CSS does not replace semantic HTML or accessibility attributes.

Developers should use appropriate HTML elements such as:

  • <header>
  • <nav>
  • <main>
  • <section>
  • <article>
  • <button>
  • <label>
  • <footer>

CSS should enhance the semantic structure rather than replace it.

Accessibility Testing

Developers should test websites in multiple ways.

Keyboard Test

Try using the entire website without a mouse.

  • Use Tab to move forward.
  • Use Shift + Tab to move backward.
  • Use Enter to activate links and buttons.
  • Use Space where appropriate for controls.

Zoom Test

Increase browser zoom and check whether content remains usable.

Contrast Test

Check whether text and important interface elements have sufficient contrast.

Responsive Test

Resize the browser and test different screen sizes.

Accessible Design Checklist

  • Text has sufficient contrast.
  • Links are visually identifiable.
  • Keyboard focus is visible.
  • Buttons have clear states.
  • Forms have visible labels.
  • Text remains readable when resized.
  • Important information is not communicated by color alone.
  • Animations respect reduced-motion preferences.
  • Interactive controls are sufficiently large and spaced.
  • Responsive layouts remain usable.

Complete Practical Example

:root {
    --primary: #2563eb;
    --primary-dark: #1d4ed8;
    --focus: #60a5fa;
    --text: #0f172a;
    --muted: #475569;
    --surface: #ffffff;
    --border: #cbd5e1;
    --background: #f8fafc;
    --radius: 12px;
}

* {
    box-sizing: border-box;
}

body {
    margin: 0;
    background: var(--background);
    color: var(--text);
    font-family: Arial, sans-serif;
    line-height: 1.6;
}

.page {
    width: min(1100px, 92%);
    margin-inline: auto;
}

.page__title {
    font-size: clamp(2rem, 5vw, 4rem);
    line-height: 1.1;
}

.course-grid {
    display: grid;
    grid-template-columns:
        repeat(auto-fit, minmax(260px, 1fr));
    gap: 24px;
}

.course-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 24px;
}

.course-card__title {
    margin-top: 0;
}

.course-card__description {
    color: var(--muted);
}

.course-card__link {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    padding: 10px 18px;
    background: var(--primary);
    color: white;
    border-radius: 8px;
    text-decoration: none;
    font-weight: 700;
}

.course-card__link:hover {
    background: var(--primary-dark);
}

.course-card__link:focus-visible {
    outline: 3px solid var(--focus);
    outline-offset: 3px;
}

@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        scroll-behavior: auto !important;
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
    }
}

Practice Exercise

Create an accessible Dwallnet course section containing six course cards.

Your project should:

  1. Use semantic HTML.
  2. Use readable typography.
  3. Use sufficient text contrast.
  4. Create visible keyboard focus states.
  5. Use :focus-visible.
  6. Provide hover and focus states for links and buttons.
  7. Use responsive CSS Grid.
  8. Use clamp() for at least one typography value.
  9. Support reduced-motion preferences.
  10. Test the website using only a keyboard.
  11. Test the website at different screen sizes.

Lesson Summary

Accessible CSS helps ensure that visual design does not become a barrier to using a website.

Developers should pay attention to color contrast, typography, focus indicators, responsive behavior, touch interactions and motion preferences.

The :focus-visible pseudo-class is useful for keyboard-friendly focus indicators, while prefers-reduced-motion allows developers to respect users who prefer less animation.

Accessibility should be considered throughout the development process rather than added at the end of a project.

Enjoying this lesson?

Sign in to your Dwallnet Academy student account to track your learning progress and mark lessons as complete.

Sign In to Track Progress