fix: update readme and arias

This commit is contained in:
Tim Rijkse
2026-01-16 11:26:39 +01:00
parent 4e650899c8
commit 7367127b50
9 changed files with 178 additions and 36 deletions

147
README.md
View File

@@ -28,6 +28,131 @@ We hebben gekozen voor een **Web Components-architectuur** om de volgende redene
--- ---
## 🎯 UX Onderbouwing
### Paginastructuur
De pagina's zijn opgebouwd volgens een bewuste hiërarchie die de gebruiker begeleidt van oriëntatie naar actie:
```
┌─────────────────────────────────┐
│ Header (sticky) │ ← Altijd toegankelijk
│ ├── Logo + Menu + Acties │
│ ├── Categorie navigatie │
│ └── Zoekbalk │
├─────────────────────────────────┤
│ Hoofdinhoud │ ← Scrollbare content
│ ├── Promotieblok (push-box) │
│ ├── Boekensecties │
│ ├── Categorieën │
│ └── Nieuwsbrief │
├─────────────────────────────────┤
│ Footer │ ← Service informatie
│ └── Accordion navigatie │
└─────────────────────────────────┘
```
### Ontwerpkeuzes per element
#### 🔍 Zoekbalk (prominent in header)
**Waarom:** De zoekfunctie staat bovenaan omdat:
- **Directe toegang** — Terugkerende klanten weten vaak al wat ze zoeken
- **Tijdsbesparing** — Sneller dan door categorieën navigeren
- **Spraakherkenning** — Extra toegankelijkheid voor gebruikers met beperkingen of onderweg
- **Verwachting** — Gebruikers verwachten een zoekfunctie bij een webshop
#### 📱 Mobile Drawer (slide-in navigatie)
**Waarom een drawer in plaats van dropdown:**
- **Meer ruimte** — Volledige schermhoogte voor uitgebreide navigatie
- **Touch-vriendelijk** — Grote klikgebieden, swipe om te sluiten
- **Focus** — Backdrop voorkomt interactie met achterliggende content
- **Overzicht** — Alle categorieën en imprints in één overzicht
- **Authenticatie** — Plek voor inlog/registratie knoppen
#### 📚 Boekkaarten (horizontale layout)
**Waarom horizontale kaarten:**
- **Scanbaarheid** — Cover links trekt de aandacht, tekst rechts geeft context
- **Efficiënt** — Meer informatie zichtbaar per kaart dan bij verticale layout
- **Touch targets** — Grote klikbare gebieden voor mobiel gebruik
- **Consistentie** — Herkenbare structuur door hele site
**Informatiehiërarchie:**
1. **Titel** (vetgedrukt, onderstreept) — Primair identificatie
2. **Beschrijving** — Context over de inhoud
3. **Auteur** (paars, onderstreept) — Secundair, maar klikbaar
4. **Prijs** (vetgedrukt) — Koopbeslissing informatie
5. **Winkelwagen knop** — Directe actie
#### 📦 Push Boxes (promotieblokken)
**Waarom push boxes:**
- **Visuele onderbreking** — Doorbreekt de lijst met boeken
- **Merkidentiteit** — Ruimte voor imprint logos (Asoka)
- **Call-to-action** — Stuurt naar belangrijke pagina's
- **Flexibiliteit** — Twee varianten (default/paars) voor verschillende contexten
**Plaatsing:**
- **Bovenaan homepage** — Introductie van het merk/imprint
- **Onder boekdetails** — Klantenservice toegang na productinfo
- **Strategisch** — Voorkomt "scroll fatigue" bij lange pagina's
#### 🏷️ Categoriekaarten (grid layout)
**Waarom visuele categorieën:**
- **Herkenning** — Iconen zijn sneller te verwerken dan tekst
- **Uitnodigend** — Visuele elementen nodigen uit tot verkennen
- **Oriëntatie** — Helpt nieuwe bezoekers het aanbod te begrijpen
- **Twee kolommen** — Optimaal voor mobiele weergave
#### 📑 Tabbladen (boekdetailpagina)
**Waarom tabs voor Beschrijving/Inzage/Recensies:**
- **Ruimtebesparing** — Voorkomt zeer lange pagina's
- **Gebruikerskeuze** — Laat gebruiker kiezen wat relevant is
- **Focus** — Toont één type informatie tegelijk
- **Verwachting** — Bekend patroon van andere webshops
#### 📰 Nieuwsbrief sectie
**Waarom onderaan (maar boven footer):**
- **Niet opdringerig** — Staat niet in de weg van productinhoud
- **Logische plek** — Na het bekijken van content, uitnodiging om verbonden te blijven
- **Visueel onderscheid** — Border maakt het herkenbaar als apart element
#### 🦶 Footer met accordions
**Waarom accordions:**
- **Ruimtebesparing** — Veel links zonder lange scrolllijsten
- **Georganiseerd** — Duidelijke categorisering van footer content
- **Touch-vriendelijk** — Grote tap targets voor mobiel
- **Verwachting** — Standaard patroon voor mobiele footers
### Visuele hiërarchie
De kleurkeuzes ondersteunen de gebruikerservaring:
| Element | Kleur | Reden |
|---------|-------|-------|
| Primaire acties | Paars (#951D51) | Opvallend, merkidentiteit |
| Links | Paars + onderstreept | Herkenbaar als klikbaar |
| Titels | Zwart + vetgedrukt | Maximaal contrast, hiërarchie |
| Secundaire tekst | Grijs | Ondersteunend, niet afleidend |
| Achtergronden | Lichtgrijs varianten | Subtiel onderscheid tussen secties |
### Scroll-gedrag header
**Smart header die inklapt bij scrollen:**
- **Naar beneden** — Header klapt deels in, meer ruimte voor content
- **Naar boven** — Header verschijnt weer, navigatie altijd bereikbaar
- **Drempel van 100px** — Voorkomt "flikkeren" bij kleine scrollbewegingen
Dit patroon maximaliseert schermruimte terwijl navigatie toegankelijk blijft.
---
## 🚀 Project starten ## 🚀 Project starten
### Vereisten ### Vereisten
@@ -255,6 +380,7 @@ Dit project is gebouwd met toegankelijkheid als prioriteit en volgt de WCAG 2.1
- Verborgen link die verschijnt bij keyboard focus - Verborgen link die verschijnt bij keyboard focus
- Stelt gebruikers in staat direct naar de hoofdinhoud te navigeren - Stelt gebruikers in staat direct naar de hoofdinhoud te navigeren
- Slaat herhalende navigatie-elementen over - Slaat herhalende navigatie-elementen over
- Geplaatst binnen de header landmark voor correcte WCAG compliance
#### Semantische HTML #### Semantische HTML
- Correcte gebruik van `<header>`, `<nav>`, `<main>`, `<footer>`, `<section>`, `<article>` - Correcte gebruik van `<header>`, `<nav>`, `<main>`, `<footer>`, `<section>`, `<article>`
@@ -289,6 +415,7 @@ Dit project is gebouwd met toegankelijkheid als prioriteit en volgt de WCAG 2.1
#### Taal #### Taal
- `lang="nl"` attribuut op HTML element - `lang="nl"` attribuut op HTML element
- Correcte taalinstelling voor screenreaders - Correcte taalinstelling voor screenreaders
- Alle ARIA labels zijn in het Nederlands
### Focus Stijlen ### Focus Stijlen
@@ -306,14 +433,24 @@ element:focus {
## 📱 Responsive Design ## 📱 Responsive Design
Het ontwerp is mobile-first gebouwd met een maximale breedte van **430px** voor de mobiele container. Op grotere schermen wordt de mobiele weergave gecentreerd weergegeven met een schaduw. > **Let op:** De huidige implementatie toont een gefixeerde mobiele container (430px) puur ter demonstratie voor deze pitch. Bij de daadwerkelijke ontwikkeling wordt de website volledig responsive gebouwd voor alle schermformaten.
### Breakpoints ### Pitch weergave
| Breakpoint | Gedrag | | Breakpoint | Gedrag |
|------------|--------| |------------|--------|
| < 431px | Volledige breedte, mobiele ervaring | | < 431px | Volledige breedte, mobiele ervaring |
| ≥ 431px | Gecentreerde container met afgeronde hoeken en schaduw | | ≥ 431px | Gecentreerde container met afgeronde hoeken en schaduw (pitch preview) |
### Geplande responsive implementatie
Bij de definitieve ontwikkeling worden de volgende breakpoints toegevoegd:
| Breakpoint | Apparaat | Aanpassingen |
|------------|----------|--------------|
| < 640px | Mobiel | Huidige ontwerp, enkele kolom |
| 640px - 1024px | Tablet | Twee-koloms grid voor boeken, aangepaste navigatie |
| > 1024px | Desktop | Volledige sidebar navigatie, drie-koloms grid, uitgebreide header |
--- ---
@@ -353,7 +490,3 @@ Front-end Developer
## 📄 Licentie ## 📄 Licentie
Dit project is gemaakt als onderdeel van een pitch voor Milinda Uitgevers en mag uitsluitend worden gebruikt indien de opdracht wordt gegund. Dit project is gemaakt als onderdeel van een pitch voor Milinda Uitgevers en mag uitsluitend worden gebruikt indien de opdracht wordt gegund.
---
*Gemaakt met ❤️ voor boeken en boeddhisme*

View File

@@ -5,9 +5,9 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta <meta
name="description" name="description"
content="Milinda - Discover and buy your next favorite book" content="Zen is opendoen - Dick Verstegen | Milinda Uitgevers"
/> />
<title>Milinda - Home</title> <title>Zen is opendoen - Milinda Uitgevers</title>
<!-- Fonts are loaded via @font-face in styles.css --> <!-- Fonts are loaded via @font-face in styles.css -->
<link rel="preconnect" href="https://fonts.googleapis.com" /> <link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
@@ -18,10 +18,12 @@
<link rel="stylesheet" href="css/styles.css" /> <link rel="stylesheet" href="css/styles.css" />
</head> </head>
<body> <body>
<a href="#main-content" class="skip-to-content">Ga naar inhoud</a>
<mobile-drawer></mobile-drawer> <mobile-drawer></mobile-drawer>
<div class="mobile-container"> <div class="mobile-container">
<site-header> <site-header>
<a href="#main-content" class="skip-to-content" slot="skip-link"
>Ga naar inhoud</a
>
<top-bar slot="top-bar"> <top-bar slot="top-bar">
<button <button
slot="menu-button" slot="menu-button"
@@ -33,10 +35,10 @@
</button> </button>
<a slot="logo" href="index.html" class="logo">Milinda</a> <a slot="logo" href="index.html" class="logo">Milinda</a>
<div slot="actions" class="actions"> <div slot="actions" class="actions">
<button class="icon-button" aria-label="Profile"> <button class="icon-button" aria-label="Profiel">
<user-icon></user-icon> <user-icon></user-icon>
</button> </button>
<button class="icon-button" aria-label="Shopping basket"> <button class="icon-button" aria-label="Winkelwagen">
<shopping-bag-icon></shopping-bag-icon> <shopping-bag-icon></shopping-bag-icon>
</button> </button>
</div> </div>
@@ -45,8 +47,8 @@
<search-bar slot="search"></search-bar> <search-bar slot="search"></search-bar>
</site-header> </site-header>
<site-content>
<main id="main-content"> <main id="main-content">
<site-content>
<section class="section"> <section class="section">
<book-details <book-details
title="Zen is opendoen" title="Zen is opendoen"
@@ -162,8 +164,8 @@
placeholder="Je e-mailadres" placeholder="Je e-mailadres"
></newsletter-signup> ></newsletter-signup>
</div> </div>
</main>
</site-content> </site-content>
</main>
<site-footer> <site-footer>
<span slot="logo">MILINDA uitgevers</span> <span slot="logo">MILINDA uitgevers</span>

View File

@@ -5,7 +5,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta <meta
name="description" name="description"
content="Milinda - Discover and buy your next favorite book" content="Milinda Uitgevers - Boeken over boeddhisme, meditatie en mindfulness"
/> />
<title>Milinda - Home</title> <title>Milinda - Home</title>
<!-- Fonts are loaded via @font-face in styles.css --> <!-- Fonts are loaded via @font-face in styles.css -->
@@ -18,10 +18,12 @@
<link rel="stylesheet" href="css/styles.css" /> <link rel="stylesheet" href="css/styles.css" />
</head> </head>
<body> <body>
<a href="#main-content" class="skip-to-content">Ga naar inhoud</a>
<mobile-drawer></mobile-drawer> <mobile-drawer></mobile-drawer>
<div class="mobile-container"> <div class="mobile-container">
<site-header> <site-header>
<a href="#main-content" class="skip-to-content" slot="skip-link"
>Ga naar inhoud</a
>
<top-bar slot="top-bar"> <top-bar slot="top-bar">
<button <button
slot="menu-button" slot="menu-button"
@@ -33,10 +35,10 @@
</button> </button>
<a slot="logo" href="index.html" class="logo">Milinda</a> <a slot="logo" href="index.html" class="logo">Milinda</a>
<div slot="actions" class="actions"> <div slot="actions" class="actions">
<button class="icon-button" aria-label="Profile"> <button class="icon-button" aria-label="Profiel">
<user-icon></user-icon> <user-icon></user-icon>
</button> </button>
<button class="icon-button" aria-label="Shopping basket"> <button class="icon-button" aria-label="Winkelwagen">
<shopping-bag-icon></shopping-bag-icon> <shopping-bag-icon></shopping-bag-icon>
</button> </button>
</div> </div>
@@ -45,8 +47,8 @@
<search-bar slot="search"></search-bar> <search-bar slot="search"></search-bar>
</site-header> </site-header>
<site-content>
<main id="main-content"> <main id="main-content">
<site-content>
<div class="content-padding"> <div class="content-padding">
<push-box> <push-box>
<img slot="logo" src="images/logo-asoka.png" alt="Asoka Logo" /> <img slot="logo" src="images/logo-asoka.png" alt="Asoka Logo" />
@@ -220,8 +222,8 @@
placeholder="Je e-mailadres" placeholder="Je e-mailadres"
></newsletter-signup> ></newsletter-signup>
</div> </div>
</main>
</site-content> </site-content>
</main>
<site-footer> <site-footer>
<span slot="logo">MILINDA uitgevers</span> <span slot="logo">MILINDA uitgevers</span>

View File

@@ -331,7 +331,7 @@ class BookDetails extends HTMLElement {
<div class="header"> <div class="header">
<div class="title-row"> <div class="title-row">
<h1 class="title">${this.bookTitle}</h1> <h1 class="title">${this.bookTitle}</h1>
<button class="favorite-btn" aria-label="Add to favorites"> <button class="favorite-btn" aria-label="Toevoegen aan favorieten">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="#f59e0b" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="#f59e0b" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/> <polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/>
</svg> </svg>

View File

@@ -110,7 +110,7 @@ class HorizontalScrollNav extends HTMLElement {
background-color: #7a1843; background-color: #7a1843;
} }
</style> </style>
<nav class="nav-container" role="navigation" aria-label="Book categories"> <nav class="nav-container" role="navigation" aria-label="Boekcategorieën">
${this.categories ${this.categories
.map( .map(
(cat) => ` (cat) => `

View File

@@ -373,8 +373,8 @@ class ImageGallery extends HTMLElement {
const imagesHtml = this.images const imagesHtml = this.images
.map( .map(
(img, index) => ` (img, index) => `
<button class="gallery-item" type="button" aria-label="View image ${index + 1}"> <button class="gallery-item" type="button" aria-label="Bekijk afbeelding ${index + 1}">
<img src="${img}" alt="Book preview ${index + 1}" class="gallery-image" /> <img src="${img}" alt="Boek voorvertoning ${index + 1}" class="gallery-image" />
</button> </button>
` `
) )
@@ -512,11 +512,11 @@ class ImageGallery extends HTMLElement {
<div class="modal-overlay"> <div class="modal-overlay">
<div class="modal-header"> <div class="modal-header">
<div class="zoom-controls"> <div class="zoom-controls">
<button class="zoom-btn zoom-out" type="button" aria-label="Zoom out"></button> <button class="zoom-btn zoom-out" type="button" aria-label="Uitzoomen"></button>
<button class="zoom-btn zoom-reset" type="button" aria-label="Reset zoom">⟲</button> <button class="zoom-btn zoom-reset" type="button" aria-label="Zoom resetten">⟲</button>
<button class="zoom-btn zoom-in" type="button" aria-label="Zoom in">+</button> <button class="zoom-btn zoom-in" type="button" aria-label="Inzoomen">+</button>
</div> </div>
<button class="modal-close" type="button" aria-label="Close"> <button class="modal-close" type="button" aria-label="Sluiten">
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<line x1="18" y1="6" x2="6" y2="18"></line> <line x1="18" y1="6" x2="6" y2="18"></line>
<line x1="6" y1="6" x2="18" y2="18"></line> <line x1="6" y1="6" x2="18" y2="18"></line>
@@ -524,7 +524,7 @@ class ImageGallery extends HTMLElement {
</button> </button>
</div> </div>
<div class="modal-content"> <div class="modal-content">
<img class="modal-image" src="" alt="Full size preview" /> <img class="modal-image" src="" alt="Volledige afbeelding" />
</div> </div>
</div> </div>
`; `;

View File

@@ -14,6 +14,8 @@ class MobileDrawer extends HTMLElement {
connectedCallback() { connectedCallback() {
this.render(); this.render();
this.setupEventListeners(); this.setupEventListeners();
// Set initial aria-hidden state
this.setAttribute("aria-hidden", "true");
} }
disconnectedCallback() { disconnectedCallback() {
@@ -51,6 +53,7 @@ class MobileDrawer extends HTMLElement {
open() { open() {
this.isOpen = true; this.isOpen = true;
this.shadowRoot.querySelector(".drawer-container").classList.add("open"); this.shadowRoot.querySelector(".drawer-container").classList.add("open");
this.setAttribute("aria-hidden", "false");
document.body.style.overflow = "hidden"; document.body.style.overflow = "hidden";
// Focus trap - focus first focusable element // Focus trap - focus first focusable element
@@ -63,6 +66,7 @@ class MobileDrawer extends HTMLElement {
close() { close() {
this.isOpen = false; this.isOpen = false;
this.shadowRoot.querySelector(".drawer-container").classList.remove("open"); this.shadowRoot.querySelector(".drawer-container").classList.remove("open");
this.setAttribute("aria-hidden", "true");
document.body.style.overflow = ""; document.body.style.overflow = "";
} }
@@ -316,7 +320,7 @@ class MobileDrawer extends HTMLElement {
<div class="drawer-container"> <div class="drawer-container">
<div class="backdrop"></div> <div class="backdrop"></div>
<nav class="drawer" aria-label="Main navigation"> <nav class="drawer" aria-label="Hoofdnavigatie">
<div class="drawer-header"> <div class="drawer-header">
<a href="index.html" class="drawer-logo">Milinda</a> <a href="index.html" class="drawer-logo">Milinda</a>
<button class="close-button" aria-label="Sluit menu"> <button class="close-button" aria-label="Sluit menu">

View File

@@ -41,9 +41,9 @@ class SiteContent extends HTMLElement {
padding-bottom: var(--spacing-md, 16px); padding-bottom: var(--spacing-md, 16px);
} }
</style> </style>
<main class="content"> <div class="content">
<slot></slot> <slot></slot>
</main> </div>
`; `;
} }
} }

View File

@@ -96,6 +96,7 @@ class SiteHeader extends HTMLElement {
} }
</style> </style>
<header class="header"> <header class="header">
<slot name="skip-link"></slot>
<slot name="top-bar"></slot> <slot name="top-bar"></slot>
<div class="collapsible"> <div class="collapsible">
<slot name="nav"></slot> <slot name="nav"></slot>