Semantic HTML: home page card grid — <ul>/<li>/<figure>/<nav> refactor

Replace presentational divs in index.php and main.css with elements that
carry correct semantic meaning, fixing multiple WCAG 2.1 AA issues:

index.php:
- <div class="cards-container"> → <ul class="cards-container"> (list of navigable items)
- <a class="card-link"><div class="card">…</div></a> → <li class="card"><a> (block link
  is the <a>, <li> is the container; removes the redundant .card div wrapper)
- <div class="card__media"> → <figure class="card__media"> when wrapping an <img>;
  gradient placeholder stays as <div> (presentational, aria-hidden)
- Improved alt text: "Couverture — [title] par [authors]" instead of bare title
- Removed <div class="card__info"> wrapper; caption is now a bare <p class="card__caption">
  directly inside the <a>
- <div class="filter-info"> → <p class="filter-info" role="status"> (live-region
  semantics; announces filter state to screen readers)
- ✕ symbol in clear-filter link wrapped in <span aria-hidden="true">
- Gradient placeholder div gets aria-hidden="true" (decorative; caption below carries text)
- Empty-state <p style="…"> → <li class="cards-empty"> (removes inline style)
- <div class="pagination-wrap"> → <nav class="pagination-wrap" aria-label="Pagination">
  with <ul>/<li> children; page-info <span> → <li aria-current="page">

main.css:
- .cards-container: add list-style:none; margin:0; padding:0 (reset <ul> defaults)
- Remove .card-link rule; replace with .card > a (block flex link, no separate class)
- .card__media: add margin:0 to reset <figure> default margin
- Remove .card__info rules; rename .authors to .card__caption with same styles
- Add .cards-empty rule (removes last inline style from index.php)
- .pagination-wrap: restructured for <nav>/<ul>; inner <ul> carries the flex layout
- prefers-reduced-motion: add .card__media--gradient guard

WCAG criteria addressed: 1.1.1 (alt text), 1.3.1 (info & relationships via semantic
list/figure), 2.4.1 (filter-info now live region), role="status" on filter banner.
This commit is contained in:
Pontoporeia
2026-03-29 16:13:02 +02:00
parent c352a392a1
commit ac872c1fe0
3 changed files with 114 additions and 94 deletions

16
TODO.md
View File

@@ -498,7 +498,7 @@ Goal: rename the tables and column to the canonical M2M pattern (`tags`, `thesis
`.tfe-back-link`, `.tfe-restricted` in `tfe.css`
- `admin/edit.php`: multiple `style=` on `.admin-form-row` and banner preview → modifier
classes in `admin.css`
- `index.php` line 146: `style="padding:2rem;color:#666;"``.cards-empty` in `main.css`
- [x] `index.php` line 146: `style="padding:2rem;color:#666;"``.cards-empty` in `main.css`
- [x] **`.site-nav__right` is a duplicate of `.site-nav__link`** - removed `.site-nav__right` block
from `common.css`; updated `nav.php` to use `.site-nav__link` on the À Propos link.
@@ -580,27 +580,27 @@ The design does **not** need to change - only the vocabulary of the markup.
### II - `public/index.php`
- [ ] **`<div class="filter-info">`** is a status/notice banner. Use `<p role="status">` or
- [x] **`<div class="filter-info">`** is a status/notice banner. Use `<p role="status">` or
`<output>` - both carry live-region semantics for screen readers without extra ARIA.
- [ ] **`<div class="cards-container">`** is a list of navigable items. Replace with `<ul>` -
- [x] **`<div class="cards-container">`** is a list of navigable items. Replace with `<ul>` -
removing the wrapper div and making each card an `<li>`. `.cards-container` → target `main > ul`
or a single class on `<ul>`.
- [ ] **`<a class="card-link"><div class="card">...</div></a>`** - the outer `<a>` wrapping a `<div>`
- [x] **`<a class="card-link"><div class="card">...</div></a>`** - the outer `<a>` wrapping a `<div>`
makes the div redundant. The `<a>` is already a block element (set `display:block`). The
`.card` div can be removed; CSS targets `ul li a` directly. The `<li>` inside the `<ul>`
becomes the card container.
- [ ] **`<div class="card__media">`** - this is the image/media wrapper inside each card.
- [x] **`<div class="card__media">`** - this is the image/media wrapper inside each card.
When it contains an `<img>`, use `<figure>` (a self-contained media unit). When it shows
the gradient placeholder (no real image), a plain `<div>` is fine since it's presentational.
- [ ] **`<div class="card__info"><p class="authors">...</p></div>`** - the `.card__info` wrapper
- [x] **`<div class="card__info"><p class="authors">...</p></div>`** - the `.card__info` wrapper
exists only to add padding. Move the padding to the `<p>` or `<li>` directly; remove the
div. The `<p>` stays. `.authors` class → either keep it or target `li > p`.
- [ ] **`<div class="pagination-wrap">`** with `<a class="pagination-btn">` and
- [x] **`<div class="pagination-wrap">`** with `<a class="pagination-btn">` and
`<span class="pagination-info">` - replace with `<nav aria-label="Pagination"><ul>...</ul></nav>`.
Each button becomes an `<li>`. The disabled state uses `aria-disabled="true"` +
`tabindex="-1"` instead of a `.disabled` class alone (which has no keyboard semantics).
@@ -927,7 +927,7 @@ Current state: **zero ARIA attributes, zero skip links, zero focus-visible style
#### 1.1.1 Non-text content (alt text)
- [ ] **Home card images use the thesis title as `alt`** - `alt="<?= $item['title'] ?>"` is a
- [x] **Home card images use the thesis title as `alt`** - `alt="<?= $item['title'] ?>"` is a
reasonable fallback, but the title alone provides no context about what the image depicts.
Prefer `"Couverture - [titre] par [auteurs]"` for cover images, or `""` (empty) for purely
decorative banners where the caption below already carries all the text information.