De aller fleste tilgjengelighetsfeil er ikke eksotiske. De er de samme ti tingene, om og om igjen. Her er de, sortert etter hvor de oppstår i koden.
1. Semantisk markup
Riktig element gir deg rolle, tilstand og tastaturhåndtering gratis. Feil element betyr at du må bygge alt selv – og som regel gjør du det ufullstendig.
<!-- Nei: ingen rolle, ingen tastaturstøtte, ingen fokus -->
<div class="btn" onclick="submit()">Send inn</div>
<!-- Ja: fungerer med tastatur, skjermleser og forms -->
<button type="submit">Send inn</button>- Én <h1> per side, og aldri hopp over nivåer nedover
- Bruk <nav>, <main>, <header>, <footer> og <aside> som landemerker
- Lister skal være <ul>/<ol>, ikke <div> med kulepunkt-ikoner
- <button> for handlinger, <a href> for navigasjon – aldri omvendt
2. Tastaturnavigasjon
Test regelen tidlig: legg fra deg musa og gå gjennom siden med Tab, Shift+Tab, Enter, mellomrom og Escape. Alt du kan gjøre med mus, skal kunne gjøres slik.
/* Nei: fjerner fokusmarkeringen for alle */
:focus { outline: none; }
/* Ja: skjuler den bare for musbrukere, og gjør den tydelig */
:focus-visible {
outline: 2px solid var(--color-brand-600);
outline-offset: 2px;
}- Fokusrekkefølgen skal følge den visuelle rekkefølgen
- Modaler skal låse fokus inne, og gi det tilbake til utløseren ved lukking
- Escape skal lukke alt som er åpnet over innholdet
- Bruk aldri positive tabindex-verdier
3. Skjema
<label for="email">E-post</label>
<input
id="email"
name="email"
type="email"
autocomplete="email"
aria-describedby="email-error"
aria-invalid="true"
/>
<p id="email-error" role="alert">Skriv inn en gyldig e-postadresse.</p>- Hvert felt trenger en synlig <label> koblet med for/id
- Plassholder er ikke en erstatning for ledetekst
- Feilmeldinger skal knyttes til feltet med aria-describedby
- Sett autocomplete på felter som gjelder brukerens egne opplysninger
- Ikke nullstill utfylte felter når validering feiler
4. Bilder og media
<!-- Informasjonsbærende: beskriv innholdet -->
<img src="/graf.png" alt="Omsetning økte fra 4 til 6,2 millioner i 2025" />
<!-- Dekorativt: tom alt, slik at skjermleseren hopper over -->
<img src="/moenster.svg" alt="" />5. Farge og kontrast
| Element | Minstekrav | Merknad |
|---|---|---|
| Brødtekst | 4,5:1 | Under 18,66 px, eller under 24 px hvis ikke fet |
| Stor tekst | 3:1 | Fra 24 px, eller 18,66 px i fet skrift |
| Grensesnittkomponenter | 3:1 | Knappekanter, ikoner, fokusmarkering |
| Fokusmarkering | 3:1 | Mot bakgrunnen den vises på |
Farge alene skal aldri være eneste bærer av informasjon. En rød ramme rundt et felt må følges av tekst som forklarer feilen.
6. Dynamisk innhold
<!-- Statusmeldinger som ikke skal avbryte brukeren -->
<div role="status" aria-live="polite">3 treff</div>
<!-- Kritiske feil som skal leses umiddelbart -->
<div role="alert">Betalingen ble avvist.</div>- Flytt fokus til nytt innhold når brukeren har utløst en navigasjon i en SPA
- Oppdater dokumenttittelen ved ruteendring
- Bruk aria-live sparsomt – for mye støy er verre enn for lite
- Kunngjør laste- og feiltilstander, ikke bare vis en spinner
7. Testing i praksis
- Automatisk i CIaxe-core via Playwright eller jest-axe fanger omtrent en tredjedel av avvikene, og hindrer regresjoner.
- Tastatur manueltGå gjennom hovedflytene uten mus. Dette avdekker mest per minutt brukt.
- SkjermleserNVDA på Windows eller VoiceOver på Mac. Du trenger ikke være ekspert for å høre at noe er galt.
- Zoom og reflow200 % tekstforstørrelse og 320 px bredde uten horisontal scrolling.
- Redusert bevegelseTest at prefers-reduced-motion faktisk slår av animasjonene dine.
import { test, expect } from "@playwright/test";
import AxeBuilder from "@axe-core/playwright";
test("forsiden har ingen alvorlige avvik", async ({ page }) => {
await page.goto("/");
const results = await new AxeBuilder({ page })
.withTags(["wcag2a", "wcag2aa", "wcag21aa", "wcag22aa"])
.analyze();
expect(results.violations).toEqual([]);
});- #Utvikling
- #WCAG
- #HTML
- #ARIA
- #Testing