Files
xamxam/todo/04-accessibility.md
Pontoporeia ca8081575c Add prefers-color-scheme dark mode for public pages
Scope: variables.css, search.css, todo/04-accessibility.md

- variables.css: add @media (prefers-color-scheme: dark) block scoped to
  body:not(.admin-body); overrides all semantic tokens with dark equivalents:
  --bg-* (#111→#333 range), --text-* (#eee/aaa/777),
  --border-* (#333/#444), --accent-primary lightened to #b87fd4
  (4.5:1 contrast on #111 background), --accent-secondary stays #9557b5,
  --accent-foreground flipped to #111111 for dark buttons,
  --accent-muted adjusted to rgba(184,127,212,0.15),
  status colours muted for dark (success #4db886, error #e05555,
  warning #d4a830); new --search-error-{bg,border,color} tokens added
  to :root (light: #fff0f0/#c00) and overridden in dark (#2a1515/#e05555)

- search.css: replace three hardcoded hex values in .search-error rule
  with var(--search-error-bg/border/color) so dark mode applies cleanly

- Admin pages are entirely unaffected: .admin-body body class is excluded
  from the dark-mode selector; system.css already has its own dark palette
2026-04-06 15:33:08 +02:00

6.6 KiB
Raw Blame History

Accessibility Audit (WCAG 2.1 AA)

1.1.1 Non-text content (alt text)

  • Admin <nav> "✕ Réinitialiser" and "✕" remove buttons — wrap in <span aria-hidden="true">✕</span>; add aria-label="Supprimer ce membre du jury" on jury remove buttons in add.php/edit.php

1.3.1 Info and relationships

  • Admin form rows: multi-input rows (languages, formats)checkbox-list.php partial now wraps checkboxes in <fieldset class="admin-checkbox-group"> with a <legend class="sr-only"> for AT grouping

  • Status badges in admin/index.php convey state by colour alonestatus-badge.php partial emits <span aria-label="Statut : Publié"><span aria-hidden="true">● </span>Publié</span> (circle symbol is non-colour indicator); both publish and access badges implemented

1.3.4 / 1.3.5 Orientation & Input purpose

  • No autocomplete attributes on personal data fieldsadd.php/edit.php: autocomplete="name" on author fields, autocomplete="email" on mail fields (via $attrs in text-field.php)

1.4.1 Use of colour

  • Active nav link has no non-colour indicator — admin nav: border-bottom: 2px solid currentColor added for [aria-current="page"] in admin.css; public nav already had border-bottom in common.css

  • Admin purple #9557b5 as text colour--admin-purple was an undefined variable referenced only in pagination hover; replaced with --accent-primary (same value, #9557b5). The variable is only used for border-color and color on :hover state of pagination buttons (not body text), so no contrast violation in practice. Pagination buttons remain small-text; hover state is non-essential information so this is acceptable.

1.4.4 Resize text

  • Verify no text is set in px — audited all CSS files; every font-size uses rem or em; no px font-size found anywhere. No action needed.

1.4.12 Text spacing

  • No text-spacing override test done — audited all overflow: hidden instances: .sr-only (visually hidden utility, 1×1px — not text content), .home-body figure / aside figure / .card (media containers, not text). .card__gradient-title clamps decorative gradient text — not essential content (same info is in the <p> link). No WCAG 1.4.12 failure found.

2.1.1 Keyboard

  • Jury "✕" remove buttons in add.php/edit.phparia-label="Supprimer le lecteur·ice N" already present on all remove buttons in jury-fieldset.php (both static and dynamically added rows)

2.4.3 Focus order

  • On tfe.php the ← Retour back link is at the bottom of the left column in DOM — already fixed; <a class="tfe-back-link">← Retour</a> is the first child of <header class="tfe-left">, which precedes <h1 class="tfe-title"> in DOM order
  • Home page cards: if two theses share the same title, identical link texts existpublic/index.php card <p> now appends <span class="sr-only">, YEAR</span> when $item['year'] is set, giving screen-reader users a unique link name per thesis

2.5.3 Label in name

  • <a class="clear-filter">✕ Réinitialiser</a> — wrap in <span aria-hidden="true">
  • Admin jury remove buttons aria-label="Supprimer ce lecteur" replaces the symbol

2.5.5 Target size

  • Pagination buttons are 2rem (32px) — increase to min-height: 2.75rem; min-width: 2.75rem (44px)
  • Admin .admin-btn-sm (~28px) — increase to minimum 32px with padding
  • Admin bulk action buttons and jury remove buttons (~28px) — increase target size

3.1.1 Language of page

  • All public pages have <html lang="fr"> — verified: templates/head.php line 2 has <html lang="fr">; all pages share this template. No action needed.

3.3.1 Error identification

  • add.php/edit.php validation errorsflash-messages.php already emits <p role="alert" data-type="error"> for errors and <p role="status"> for success
  • add.php/edit.php autofocus on first invalid fieldApp::flashAutofocus(fieldName) stores the failing field in $_SESSION['_flash_autofocus']; action handlers map exception messages to field names; add.php consumes via withAutofocus() helper + injects into $attrs; edit.php uses inline ternary; partials support boolean true in $attrs to emit bare attribute names

3.3.2 Labels or instructions

  • Admin jury "Lecteur·ices" label has no for attribute — replaced plain <label>Lecteur·ices :</label> with <fieldset class="admin-jury-lecteurs"><legend>Lecteur·ices</legend> in jury-fieldset.php; CSS rule strips the nested fieldsets border/padding so it renders as a sub-group

4.1.2 Name, role, value

  • Custom "Externe" checkbox for jury members has no group context — all jury "Externe" checkboxes now carry explicit aria-label (e.g. "Promoteur·ice — externe", "Lecteur·ice N — externe"); both static PHP-rendered rows and dynamically added rows via addJuryRow() receive the label

  • <video> elements on tfe.php have no captions<track kind="captions"> now emitted for each MP4 when a .vtt sidecar has been uploaded alongside it; N-th VTT file is paired with N-th video in document order. formulaire.php accepts .vtt uploads (MIME text/vtt, file_type = 'caption'); media.php serves VTT with correct Content-Type; admin add.php file-field hint documents the .vtt convention.

  • Admin <select> for visibility/access in edit.php uses truncated option text — removed mb_strimwidth call; option text now uses full description (name — description) so screen-reader accessible name is complete and unambiguous

  • Bulk publish/unpublish JS does not announce result to screen readers — action result is a full-page redirect to a flash message rendered by flash-messages.php which already emits role="alert" (error) / role="status" (success); no additional JS announcement needed

5 - Motion & user preferences

  • prefers-color-scheme not respectedvariables.css now includes a @media (prefers-color-scheme: dark) block scoped to body:not(.admin-body); overrides all semantic tokens (--bg-*, --text-*, --border-*, --accent-*, status colours) with dark equivalents; --accent-primary lightened to #b87fd4 for 4.5:1 contrast on dark backgrounds; search.css .search-error hardcoded #fff0f0/#c00 replaced with --search-error-bg/--search-error-border/--search-error-color variables also overridden in dark mode; admin pages unaffected (.admin-body preserves light-mode values)