A11y
Et indblik

Braille

Webtilgængelighed
Hvad forbinder du med A11Y?
Tre stikord
Sum med sidemakkeren

Webtilgængelighed er ofte fejlopfattet som separat disciplin eller en eftertanke
Compliance-bestræbelser fører til tjeklistementalitet

Jakoba Mulderhuis i Amsterdam
Bygningen opfylder DS/ISO 21542-standarden for tilgængelighed








Lovgivning
Lov om tilgængelighed af offentlige organers websteder og mobilapplikationer
Lov om tilgængelighedskrav for produkter og tjenester
juni 2021
juni 2025
Lov om tilgængelighedskrav for produkter og tjenester
Påvirker produkter, der leveres fra 28. juni 2025
Påvirker alle produkter fra 28. juni 2030
Lov om tilgængelighedskrav for produkter og tjenester
Produkter og tjenester må kun bringes i omsætning eller leveres, hvis de opfylder de relevante tilgængelighedskrav
tjeklistementalitet
Tilgængelighedskrav
"...mere end én sensorisk kanal"
Understandable (forståelig)
Perceivable (opfattelig)
Operable (anvendelig)
Robust
"...hensyn til forventede anvendelsesforhold"
"...på en forståelig måde"
"...som brugerne kan opfatte"
LOV nr 801
Det kan løst oversættes til retningslinjerne for WCAG 2.1

Tilgængelighedskrav
Understandable (forståelig)
Perceivable (opfattelig)
Operable (anvendelig)
Robust
Tilgængelighedsprincipper

Tilgængelighedskrav
Understandable (forståelig)
Perceivable (opfattelig)
Operable (anvendelig)
Robust
Tilgængelighedsprincipper

at billeder gøres opfattelige for skærmlæserprogrammer ved at tekstliggøre billederne
Tilgængelighedskrav
Understandable (forståelig)
Perceivable (opfattelig)
Operable (anvendelig)
Robust
Tilgængelighedsprincipper

at webstedet er anvendeligt for brugere, der bruger tastatur og ikke mus
Tilgængelighedskrav
Understandable (forståelig)
Perceivable (opfattelig)
Operable (anvendelig)
Robust
Tilgængelighedsprincipper

at webstedet er anvendeligt for brugere, der bruger tastatur og ikke mus
Tilgængelighedskrav
Understandable (forståelig)
Perceivable (opfattelig)
Operable (anvendelig)
Robust
Tilgængelighedsprincipper

at en digital selvbetjeningsløsning er forståelig ved at tilbyde fejlforslag og instruktioner ved indtastning af fejl
Tilgængelighedskrav
Understandable (forståelig)
Perceivable (opfattelig)
Operable (anvendelig)
Robust
Tilgængelighedsprincipper

at webstedet er robust ved at benytte kodning korrekt, så brugerens værktøjer kan fortolke dem ensartet
Tilgængelighedskrav
Dokumentation


A11Y handler om brugssituationer
Kan interfacet opfattes, betjenes og forstås?
Tilgængelighed
Tilgængelighed
Inclusive design
Tilgængelighed
Inclusive design
Usability design
Compliance

Fra “Practical Accessibility” af Sara Soueidan
Tilgængelighed
Grupper


Tilgængelig for alle
og brugervenlig


compliance ≠ brugervenlig
Tastatur og fokus
Kan alle betjene det — og se hvor de er?
Gå frem: ⇥ (Tab)
Gå tilbage: ⇧⇥ (Shift+Tab)
Aktivér: ↵ (Enter)
Øvelse 1: Tivoli
- Gå til https://shop.tivoli.dk/
- Kun ved hjælp af tastaturet, naviger til “Forny dit Tivolikort”
- Find ud af, hvordan man finder sit kortnummer
Tastatur og fokus
Hvilke udfordringer støder du på?
Gå frem: ⇥ (Tab)
Gå tilbage: ⇧⇥ (Shift+Tab)
Aktivér: ↵ (Enter)
Øvelse 2: Tivoli
- Gå fra “Køb billetter“-siden til “Turpas”-siden
- Vælg datoen for i morgen
- Accepter dags dato og vælg 2 antal Turpas
- Læg i kurv
- Vælg “Shop videre”
Tastatur og fokus
Hvilke udfordringer støder du på?
Tastatur-brugere
- Focus styles
-
Tab order
-
Skip links

Focus styles
Kontrast
:focus-visible {
outline: 3px solid black;
box-shadow: 0 0 0 6px white;
}Focus-styles skal være tydeligt synlige ved tastaturnavigation, have mindst 3:1 kontrast, svare til mindst arealet af en 2 CSS-px ramme og ikke være skjult.
Fjern aldrig outline uden en tilgængelig erstatning!
Universel?
Focus styles
Kontrast
:focus-visible {
outline: 3px solid black;
box-shadow: 0 0 0 6px white;
}Hvad kan fokuseres?
Focus styles
<a href=""></a>
<input>
<select></select>
<textarea></textarea>
<button></button>
<iframe></iframe>
<div tabindex="0"></div> <!-- > 0 -->
<div style="overflow: auto;"></div> <!-- Måske -->- tabindex=”-1”: Gør elementer fokuserbare, men inkluderer ikke i tab-rækkefølge
- tabindex=”0”: Inddrager element i tab-rækkefølgen
- tabindex=”5”: Overskriver tab-rækkefølgen
<div class="button" tabindex="0">Træls knap</div>Hvad kan fokuseres?
Focus styles
Tab-rækkefølgen
Tab order


Firefox
Spring navigationen over
Skip links
Spring navigationen over
Skip links
<a href="#main" class="skip-links">Skip to main content</a>
<main id="main">…</main>- Alt skal kunne betjenes fra tastaturet. Så brugere, der ikke kan bruge musen også har en chance.
- Der skal være synligt tastaturfokus. Så vi kan se, hvor vi er, når vi navigerer med tastaturet.
- Tilbyd mulighed for at springe over menuer/indhold. Så brugeren ikke får ondt i tungen.
- Undgå tastaturfæller. Så man ikke som tastaturbruger hænger fast uden at kunne komme tilbage, videre eller væk.
Tastatur-brugere
Krav




mandatory
Omkring 20-30%
Begrænsninger ved automatiserede tests
- Fokustilstande
- Test af interaktioner (dropdownmenuer og modaler)
- Trykflader (24x24)
- 200%-400% zoom
- Reduced motion-animationer
- End-to-end-tests
Extensions & Tools
axe Accessibility Linter

DevTools

- button
- link
- heading
- list
- navigation
- osv.
Roller
- toolbar
- tablist
- tab
- tabpanel
- status
- osv
HTML elementer
ARIA
WAI-ARIA
Med ARIA kan vi formidle mere komplekse elementer, som vi kender fra operativsystem-grænsefladen men som ikke er en standard del af html.
Accessible Rich Internet Applications
WAI-ARIA
Skærmlæsere kommunikerer via accessibility API (accessibility tree).
- ARIA opdaterer role, state og property i accessibility tree.
- ARIA ændrer ikke på browserens opførsel.

WAI-ARIA
Der er tre typer ARIA attributter.
- Role
- State
- Property
WAI-ARIA
- Siger hvad et element er (button, dialog, radiogroup).
- Et element må ikke dynamisk skifte rolle.
- Nogle roller er afhængige af andre, fx listitem i list.
- Nogle roller er landmarks, nav, main, search.
Role
WAI-ARIA
Siger noget om elementets tilstand fx aria-checked, aria-pressed, aria-expanded.
State
WAI-ARIA
Siger noget om en egenskab ved elementet fx aria-label, aria-labelledby, aria-haspopup, aria-level.
Property
State
<button
aria-expanded="false"
aria-controls="widget1">
Toggle widget
</button>fortæller om noget er åbent
fortæller, hvad der åbnes/lukkes

State
button.addEventListener("click", () => {
panel.hidden = !panel.hidden;
button.ariaExpanded = !panel.hidden;
});Toggle state

Invokers i HTML
"Gratis" tilgængelighed
<button
command="show-modal"
commandfor=".."
interestfor="...">
Åben popover
</button>
<details>
<summary>Åben</summary>
...
</details>
Skærm-
læser
Siden som navigerbar struktur
Overskrifter, landmarks og komponenter
Overskrifter
Hierarki
<body>
<main>
<h1>I describe the page's primary topic</h1>
<section>
<h2>A child section</h2>
<section>
<h3>A sub-section of the child section</h3>
</section>
</section>
</main>
</body>
Overskrifter
Hierarki


Øvelse
- Installér HeadingsMap.
- Besøg BBC Travel
- Aktivér HeadingsMap
- Tal med sidemakkeren om overskrifthierarkiet
- Vi samler op
Overskrifter
Hierarki



span
Overskrifter
Hierarki
Hvorfor er det udfordrende?
Overskrifthierarki
Svar: Moderne webudvikling
function ProductCard({ product }) {
return (
<article>
<h2>{product.name}</h2>
<p>{product.price}</p>
</article>
);
}
Moderne webudvikling
<main>
<h1>Søgeresultater</h1>
<ProductCard product={vomero} />
</main>
✅
function ProductCard({ product }) {
return (
<article>
<h2>{product.name}</h2>
<p>{product.price}</p>
</article>
);
}
Moderne webudvikling
<main>
<h1>Sneakers</h1>
<section>
<h2>Populære lige nu</h2>
<ProductCard product={vomero} />
</section>
</main>
🚫
h1 Sneakers
├── h2 Populære lige nu
└── h2 Nike Zoom Vomero 5
function ProductCard({headingLevel, title, children}) {
const Heading = `h${headingLevel}`;
return (
<article>
<Heading>{title}</Heading>
{children}
</article>
);
}
Manuelt
<ProductCard
headingLevel={3}
title="Nike Zoom Vomero 5">
<p>1.299 kr.</p>
</ProductCard>
props
const HeadingLevelContext = createContext(1);
function Section({ title, children }) {
const parentLevel = useContext(HeadingLevelContext);
const level = parentLevel + 1;
const Heading = `h${level}`;
if (level > 6) {
throw new Error("Indholdsstrukturen er mere end seks niveauer dyb");
}
return (
<section>
<Heading>{title}</Heading>
<HeadingLevelContext.Provider value={level}>
{children}
</HeadingLevelContext.Provider>
</section>
);
}
Automatiseret
context
Nær fremtid
<body>
<main>
<h1>I describe the page's primary topic</h1>
<section headingoffset="1">
<h1>A child section</h1>
<section headingoffset="1">
<h1>A sub-section of the child section</h1>
</section>
</section>
</main>
</body>
headingoffset
:heading(1) { ... }
:heading(2) { ... }
:heading(3) { ... }
/* ... */
Kobler til de rigtige aria-roller
Er sections mere semantiske end div'er?
<body>
<main>
<section> <!-- er jeg semantisk? -->
</section>
</main>
</body>
Landmarks
Navigation via regioner
Landmarks
Typer af regioner
bannernavigationsearchmainregioncomplementaryformcontentinfo
Landmarks
Indbygget i HTML-elementer
bannernavigationsearchmainregioncomplementaryformcontentinfo
<header> (direkte barn af body)
<nav>
<search>
<main>
<section> (hvis den har et navn)
<aside>
<form> (hvis den har et navn)
<footer> (direkte barn af body)
Landmarks
Indbygget i HTML-elementer
banner
complementary
main
region / form
contentinfo
navigation
Er sections semantiske?
<body>
<main>
<section aria-label="Min region"> <!-- Nu er jeg -->
<h2>Overskrift</h2>
</section>
</main>
</body>
Er sections semantiske?
<body>
<main>
<section aria-labelledby="region-title"> <!-- Nu er jeg -->
<h2 id="region-title">Overskrift</h2>
</section>
</main>
</body>
Men ikke alle bør ikke være det!
Hvornår bør en section være et region landmark?
<nav></nav>
Landmarks
Navngiv vigtige landmarks
Hvilken navigation?
<nav aria-label="Hovedmenu"></nav>
<nav aria-labelledby="breadcrumb">
<h2 id="breadcrumb">Brødkrumme</h2>
...
</nav>
Landmarks
Navngiv vigtige landmarks
"Hovedmenu navigation"
"Brødkrumme navigation"
Åbn "Opgave" fra repo og lav første del:
Headings, landmarks og disclosure-knap
Opgave, del 1
Øvelse

Hvad hedder knappen?
Det synlige interface er ikke hele interfacet






- Gå til IKEA
- Find ud af, hvor navnet kommer fra
Øvelse


.visually-hidden
Overskrifter
Hvad ser I?

.visually-hidden
.visually-hidden {
border: 0;
clip-path: inset(50%);
height: 1px;
margin: 0;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
.visually-hidden
.visually-hidden {
border: 0;
clip-path: inset(50%);
height: 1px;
margin: 0;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
<button>
<span class="fa fa-tweet" aria-hidden="true"></span>
<span class="label"> Tweet </span>
</button>
aria-hidden="true"
Skjul for UI
Skjul for Skærmlæser
Hvad hedder knappen?
accName


<button>
Add <span class="visually-hidden">[ PRODUCT_NAME ]</span> to Cart
</button>
<button>
Add to Cart <span class="visually-hidden">, [ PRODUCT_NAME ]</span>
</button>
<a href="/path/to/article-title/">Læs mere</a>
<a href="/path/to/article-title/">
Læs mere <span class="visually-hidden">om [ ARTIKELNAVN ]</span>
</a>✅
❌
Sammensatte navne
Hvornår er noget dekorativt?
Analyse
Live-opdateringer
<p role="status"></p>Lav anden del:
Accessible names, states, billedalternativer og status
Opgave, del 2
Øvelse

IT-hjælpemidler* er afhængige af semantik for at præsentere information samt for at skabe en grænseflade til navigation for brugeren.
* Assistive technologies, såsom skærmlæsere
HTML
At vælge semantiske HTML-elementer er ikke altid nok...
Og CSS kan endda påvirke semantikken...
ul {
list-style: none;
}
HTML-semantik påvirkes også af
ARIA-attributter
<button
aria-expanded="true"
aria-controls="panel">
Open
</button>
Og kan tilføre semantik til generiske elementer, såsom div og span
<div role="button">
Open
</div>
Hvordan et element annonceres af en skærmlæser afhænger af den browser, platform og skærmlæserkombination, som brugeren anvender.
WebDev - A11y
By Dannie Vinther
WebDev - A11y
A11y
- 92