diff --git a/.eleventy.js b/.eleventy.js index 746270e8..a6edf3b1 100644 --- a/.eleventy.js +++ b/.eleventy.js @@ -5,6 +5,7 @@ const { DateTime } = require("luxon"); const pluginAddIdToHeadings = require("@orchidjs/eleventy-plugin-ids"); const pluginRss = require("@11ty/eleventy-plugin-rss"); const brokenLinksPlugin = require("eleventy-plugin-broken-links"); +const syntaxHighlight = require("@11ty/eleventy-plugin-syntaxhighlight"); module.exports = function (eleventyConfig) { const quick = Boolean(process.env.BUILD_QUICK); @@ -80,6 +81,8 @@ module.exports = function (eleventyConfig) { eleventyConfig.addPlugin(pluginRss); + eleventyConfig.addPlugin(syntaxHighlight); + /** * Rebuild when any of the files are changed, but exclude css because that is * handled by the asset pipeline. diff --git a/package-lock.json b/package-lock.json index 8b49e48c..c838c280 100644 --- a/package-lock.json +++ b/package-lock.json @@ -214,6 +214,7 @@ "resolved": "https://registry.npmjs.org/@11ty/eleventy-plugin-syntaxhighlight/-/eleventy-plugin-syntaxhighlight-5.0.0.tgz", "integrity": "sha512-y9BUmP1GofmbJgxM1+ky/UpFCpD8JSOeLeKItUs0WApgnrHk9haHziW7lS86lbArX5SiCVo4zTTw9x53gvRCaA==", "dev": true, + "license": "MIT", "dependencies": { "prismjs": "^1.29.0" }, diff --git a/src/_assets/css/common/code.css b/src/_assets/css/common/code.css new file mode 100644 index 00000000..f0c3dbe7 --- /dev/null +++ b/src/_assets/css/common/code.css @@ -0,0 +1,202 @@ +pre:has(code) { + position: relative; + display: block; + margin: 1rem -20px; + padding: 20px; + + code { + background-color: transparent; + } + + &::before { + position: absolute; + right: 20px; + top: 0px; + padding: 0.5rem 0.5rem 0.75rem; + line-height: 1; + font-size: 0.875rem; + content: ""; + display: block; + text-align: right; + background: var(--lilac); + color: black; + font-weight: bold; + clip-path: polygon( + 0 0, + 100% 0, + 100% calc(100% - 0.5rem), + 50% 100%, + 0 calc(100% - 0.5rem) + ); + } + + &:has(code.language-html)::before { + content: "HTML"; + } + &:has(code.language-css)::before { + content: "CSS"; + } + &:has(code.language-js)::before { + content: "JS"; + } +} + +/** + * a11y-dark theme for JavaScript, CSS, and HTML + * Based on the okaidia theme: https://github.com/PrismJS/prism/blob/gh-pages/themes/prism-okaidia.css + * @author ericwbailey + */ + +code[class*="language-"], +pre[class*="language-"] { + color: #f8f8f2; + background: none; + font-family: Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace; + text-align: left; + white-space: pre; + word-spacing: normal; + + word-break: normal; + word-wrap: normal; + line-height: 1.5; + + -moz-tab-size: 4; + -o-tab-size: 4; + tab-size: 4; + + -webkit-hyphens: none; + -moz-hyphens: none; + -ms-hyphens: none; + hyphens: none; +} + +/* Code blocks */ +pre[class*="language-"] { + overflow: auto; +} + +:not(pre) > code[class*="language-"], +pre[class*="language-"] { + background: #2b2b2b; +} + +/* Inline code */ +:not(pre) > code[class*="language-"] { + padding: 0.1em; + border-radius: 0.3em; + white-space: normal; +} + +.token.comment, +.token.prolog, +.token.doctype, +.token.cdata { + color: #d4d0ab; +} + +.token.punctuation { + color: #fefefe; +} + +.token.property, +.token.tag, +.token.constant, +.token.symbol, +.token.deleted { + color: #ffa07a; +} + +.token.boolean, +.token.number { + color: #00e0e0; +} + +.token.selector, +.token.attr-name, +.token.string, +.token.char, +.token.builtin, +.token.inserted { + color: #abe338; +} + +.token.operator, +.token.entity, +.token.url, +.language-css .token.string, +.style .token.string, +.token.variable { + color: #00e0e0; +} + +.token.atrule, +.token.attr-value, +.token.function { + color: #ffd700; +} + +.token.keyword { + color: #00e0e0; +} + +.token.regex, +.token.important { + color: #ffd700; +} + +.token.important, +.token.bold { + font-weight: bold; +} + +.token.italic { + font-style: italic; +} + +.token.entity { + cursor: help; +} + +@media screen and (-ms-high-contrast: active) { + code[class*="language-"], + pre[class*="language-"] { + color: windowText; + background: window; + } + + :not(pre) > code[class*="language-"], + pre[class*="language-"] { + background: window; + } + + .token.important { + background: highlight; + color: window; + font-weight: normal; + } + + .token.atrule, + .token.attr-value, + .token.function, + .token.keyword, + .token.operator, + .token.selector { + font-weight: bold; + } + + .token.attr-value, + .token.comment, + .token.doctype, + .token.function, + .token.keyword, + .token.operator, + .token.property, + .token.string { + color: highlight; + } + + .token.attr-value, + .token.url { + font-weight: normal; + } +} diff --git a/src/_assets/css/style.css b/src/_assets/css/style.css index 45d40cdf..9c179e48 100644 --- a/src/_assets/css/style.css +++ b/src/_assets/css/style.css @@ -6,6 +6,7 @@ @import "./common/layout.css"; @import "./common/skiplink.css"; @import "./common/forms.css"; +@import "./common/code.css"; @import "./elements/button.css"; @import "./elements/page-navigation.css"; diff --git a/src/_assets/member-avatars/kilian-valkhof.jpg b/src/_assets/member-avatars/kilian-valkhof.jpg new file mode 100644 index 00000000..f8e79a98 Binary files /dev/null and b/src/_assets/member-avatars/kilian-valkhof.jpg differ diff --git a/src/_components/shortcodes/tag/tag.css b/src/_components/shortcodes/tag/tag.css index 561b812b..156b7809 100644 --- a/src/_components/shortcodes/tag/tag.css +++ b/src/_components/shortcodes/tag/tag.css @@ -1,4 +1,4 @@ -.tag { +.tag:not(.token) { position: relative; display: inline-flex; justify-content: space-between; @@ -22,10 +22,10 @@ /* Rounded tags, like with { and } */ .tag-curly-braces { - -webkit-clip-path: url(#button-curly-braces); + -webkit-clip-path: url(#button-curly-braces); clip-path: url(#button-curly-braces); } -.tag + .tag { +.tag:not(.token) + .tag:not(.token) { margin-inline-start: 2em; } diff --git a/src/en/blog/2024/12/what-determines-the-accessible-name-of-an-element.md b/src/en/blog/2024/12/what-determines-the-accessible-name-of-an-element.md new file mode 100644 index 00000000..b266e418 --- /dev/null +++ b/src/en/blog/2024/12/what-determines-the-accessible-name-of-an-element.md @@ -0,0 +1,181 @@ +--- +title: What determines the accessible name of an element? +date: 2024-12-26 +author: Kilian Valkhof +summary: "The accessible name of an element is how the browser passes an element to assistive technologies like screen readers or braille displays, and forms the way someone who cannot (fully) see a site consumes the content." +categories: + - Advent Calendar +key: advent-2024-kilian +--- + +## The role of elements + +Whether an element has an accessible name depends on the _role_ that element has on the page. Some elements automatically get an accessible name, such as a button, a link, or a heading. A div has no accessible name because a div has no role. Even if you give a div an explicit accessible name (more on that later in the article), the browser will ignore this until a relevant role is also assigned to the div. + +Through these roles, browsers and assistive technologies can determine which parts of a page are relevant at what time. If a user wants to quickly _skim_ through the page, assistive technology will only read out elements with the role _heading_. If a user wants to quickly navigate to the navigation, assistive technology will only read out landmark elements. This way, users don't have to wade through the entire page to find what they're looking for. + +Some of these roles are baked into the HTML you use, which is why it's important to use HTML elements with the correct semantics. This not only gives you the role of an element but also the "batteries included" interaction: You don't need to make a button focusable and clickable yourself. If you assign roles yourself, you'll also need to add the interaction yourself. + +However, not everything you want to build on a site can be built with HTML; sometimes you need to build a more complex component with generic elements. In that case, you'll work with ARIA roles yourself. If you want to create an interface with tabs, for example, ARIA has the roles tab, tabpanel, and tablist to build that accessibly. + +Don't think that at the end of this article you'll be tasked with providing all your elements with an explicit accessible role and name: write good HTML and you'll already get quite far. + +## Accessible names + +In its simplest form, it's the text within an element. Take this button for example: + +```html + +``` + +The accessible name of this button is "Add". So far so good. But maybe I want to add an icon: + +```html + +``` + +The attentive reader notices that this image has a proper alt attribute describing the image. However, the content of that alt attribute also counts towards the button's accessible name. So the accessible name of this button is "Add icon of a shopping cart". And that's not very helpful. Since we already have the text "Add" in the button, the icon is only for decoration. A better solution is to use an empty alt attribute: + +```html + +``` + +The accessible name is now "Add" again, yay! + +Time for the next step: The button has no visible text anymore, just the icon. The accessible name is now an empty string, and that's not helpful: we can no longer use the element's content for the accessible name. + +We can solve this in several ways, starting with an aria attribute specifically meant for this: `aria-label`. + +```html + +``` + +When an element (one with a role supporting accessible names) has an `aria-label` attribute, the content of the element is **completely ignored**. The accessible name of this button is now "Add", regardless of what's in the element. This can quickly lead to problems. + +Let's say we get an urgent ticket to add a "Remove" button next to the Add button. We quickly copy the Add button's code, attach a different event handler, and change the icon to a trash can. + +```html + +``` + +We refresh the browser and the icon looks great and works when clicked. Ship it! + +...But we overlooked that aria-label: we _literally can't see it_ in the browser. So you need to be very careful to also update the aria-label when you update an element's content. Another problem with aria-label is that if your browser can automatically translate the page, the aria-label won't be translated ([aria-label does not translate](https://adrianroselli.com/2019/11/aria-label-does-not-translate.html)). + +Let's try another solution instead, screenreader-only text: + +```html + +``` + +".sr-only" is not a built-in standard, but a convention (with accompanying CSS) that is widely used. This is an example of .sr-only CSS: + +```css +.sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border: 0; +} +``` + +This CSS ensures that the content is absolutely not visible but can still be read by a screen reader. This way we can determine the accessible name with "normal" text that can also be automatically translated. Figuring out how the CSS does that is something for another article. + +By the way, there is discussion about whether such a class should be built into browsers. [Ben Myers](https://benmyers.dev/blog/native-visually-hidden/) is in favor, [Scott o'Hara](https://www.scottohara.me/blog/2023/03/21/visually-hidden-hack.html) is against. Both articles are worth reading. + +The accessible name of the above buttons is thus determined in this order: + +1. Is there an aria-label attribute? Use that. +2. If not, use the content of the element. + +However, this is an extremely simplified order. To understand the rest of the 'accessible name' algorithm, we'll make our example more complex. We now have two buttons, each adding something different: + +```html +
Nice and warm
+ + +Looks good on you
+ +``` + +The accessible name of these buttons is now "Add". But that's not helpful, because one button adds a hoodie and the other a cap. If you can see where the buttons are located, that's clear, but otherwise you have a problem. What we want here is to explicitly link the button to its corresponding product. We can do that with an `aria-labelledby` attribute: + +```html +Nice and warm
+ + +Looks good on you
+ +``` + +With `aria-labelledby` we can specify an ID of another element, and the accessible name of the button becomes the text of that element. Like `aria-label`, the content of the element is then ignored, and that's still a problem because how does a user know the button is for "Add"? + +`aria-labelledby` solves this because you can give it not just one ID, but a list. The accessible name of the button then becomes the text of all elements you specify, separated by spaces. If we give our buttons an ID as well, we can also add the button's own text: + +```html +Nice and warm
+ + +Looks good on you
+ +``` + +The accessible name of these buttons is now "Fronteers hoodie Add" and "Fronteers cap Add". This is much clearer for a user who cannot see what's on the page. + +But wait a minute, we just learned that aria-labelledby on an element ignores the content of that element. How can it be that the button's own text is now being read out? Doesn't this become an _infinite loop_? + +Fortunately not! When you reference an element via `aria-labelledby`, it looks at the accessible name of that element as if there was no aria-labelledby attribute. Aria-labelledby only applies to the first step and you therefore don't get tangled up. This has been thought through! + +Another thing that's been thought through: all text that now forms the accessible name is text on the page: so it can be translated normally. + +With `aria-labelledby` added, this is the order in which the accessible name is determined: + +1. Is there an `aria-labelledby` attribute AND is this the first element for which you're determining the accessible name? Use the text of the elements you specify, separated by a space. +2. Is there an aria-label attribute? Use that. +3. If not, use the content of the element. + +## Conclusion + +Hopefully you now have a better idea of where the accessible name of elements comes from, why you sometimes want to change it, and how to do that properly. + +Unfortunately, I have to tell you that the algorithm for determining an accessible name is much more complicated. This complexity exists mainly to provide for cases where the above doesn't work. For certain types of input elements that have no content, for example, it looks at the `value`. Is there no value but is it a button type, like ``? Then it gets the accessible name "Submit" from the browser. Empty textareas get the accessible name from the `title` or `placeholder` attribute. And there are many more exceptions. And as the very, very last resort, the `title` attribute of an element is used. + +This is explicitly a last resort for when the developer hasn't done their job. If you're consciously working with accessible names then look at the three options: text on the page, aria-label, and aria-labelledby. + +Want to read more about accessible name calculation? Here you can find a clear explanation: [Accessible name calculation](https://www.w3.org/WAI/ARIA/apg/practices/names-and-descriptions/#name_calculation) and if you really want to dive in, you can find the specification here: [Accessible Name and Description Computation](https://www.w3.org/TR/accname-1.2/). But be warned, it's quite intense. diff --git a/src/en/members/kilian-valkhof.md b/src/en/members/kilian-valkhof.md new file mode 100644 index 00000000..e63a7749 --- /dev/null +++ b/src/en/members/kilian-valkhof.md @@ -0,0 +1,30 @@ +--- +published: true +draft: false + # Jouw naam +title: Kilian Valkhof + # Maak van de key een unieke slug (je voor en achternaam bijvoorbeeld). Hiermee wordt de Nederlandse aan de Engelse versie van deze pagina gekoppeld. +key: kilian-valkhof +date: 2020-11-10 + # Als je een afbeelding toevoegt, link dan hier naar de juiste plek: +graphic: + src: /assets/images/member-avatars/kilian-valkhof.jpg + alt: Kilian Valkhof +# Jouw functietitel +jobtitle: 'Product developer' +# Eventueel: jouw huidige werk- of opdrachtgever +employer: 'Polypane browser for developers' +specialties: + - accessibility + - responsive design + - product development + - developer tools + - ux design +--- + +Kilian is the creator of Polypane, a browser for developers. He has a passion for building tools that make developers' lives easier and more productive. + +- [Kilianvalkhof.com](https://kilianvalkhof.com) +- [Polypane.app](https://polypane.app) +- [Superposition.design](https://superposition.design) +- [Fixa11y.com](https://fixa11y.com) \ No newline at end of file diff --git a/src/nl/blog/2024/12/wat-bepaalt-de-toegankelijke-naam-van-een-element.md b/src/nl/blog/2024/12/wat-bepaalt-de-toegankelijke-naam-van-een-element.md new file mode 100644 index 00000000..0e382660 --- /dev/null +++ b/src/nl/blog/2024/12/wat-bepaalt-de-toegankelijke-naam-van-een-element.md @@ -0,0 +1,177 @@ +--- +title: Wat bepaalt de toegankelijke naam van een element? +date: 2024-12-26 +author: Kilian Valkhof +summary: "De toegankelijke naam van een element is hoe de browser een element doorgeeft aan hulptechnologieën zoals een screenreader of braille bord, en vormt de manier waarop iemand die een site niet (goed) kan zien de inhoud tot zich neemt." +categories: + - Adventskalender +key: advent-2024-kilian +--- + +## De rol van elementen + +Of een element een toegankelijk naam heeft of niet ligt aan de _rol_ die een element heeft op de pagina. Sommige elementen krijgen automatisch een toegankelijke naam, zoals een button, een link of een koptekst. Een div heeft geen toegankelijke naam, want een div heeft geen rol. Ook al geef je een div een expliciete toegankelijke naam (meer daarover later in het artikel), dan zal de browser dit negeren totdat er ook een relevante rol aan de div wordt toegekend. + +Door die rollen kunnen browsers en hulptechnologieen bepalen welke delen van een pagina op welk moment relevant zijn. Wil een gebruiker snel door de pagina heen _skimmen_, dan zal een hulptechnologie enkel de elementen met rol _heading_ voorlezen. Wil een gebruiker snel naar de navigatie, dan zal een hulptechnologie enkel landmarkelementen voorlezen. Zo hoeft een gebruiker niet de hele pagina door te ploegen om te vinden wat hij zoekt. + +Een deel van de rollen is dus inherent aan de HTML die je gebruikt, en waarom het belangrijk is om de HTML-elementen met de juiste semantiek te gebruiken. Daarmee krijg je niet alleen de rol van een element, maar ook de "batteries included" interactie: Een button hoef je niet zelf focusbaar en klikbaar te maken. Ga je zelf rollen toewijzen, dan moet je ook zelf de interactie toevoegen. + +Niet alles wat je op een site wilt bouwen kan je echter bouwen met HTML, soms moet je met generieke elementen een complexer component bouwen. In dat geval ga je zelf met ARIA-rollen aan de slag. Wil je een interface met tabjes maken, dan heeft ARIA bijvoorbeeld de rollen tab, tabpanel en tablist om dat toegankelijk op te bouwen. + +Denk vooral niet dat aan het einde van dit artikel je de taak staat te wachten om al je elementen van een expliciete toegankelijke rol en naam te voorzien: schrijf goede HTML en je komt al een heel eind. + +## Toegankelijke namen + +In de meest simpele vorm is dat de tekst in een element. Neem bijvoorbeeld deze button: + +```html + +``` + +De toegankelijke naam van deze button is "Toevoegen". So far so good. Maar misschien wil ik er wel een icoontje aan toevoegen: + +```html + +``` + +Een oplettende lezer ziet dat deze afbeelding netjes een alt attribuut heeft dat de afbeelding beschrijft. De inhoud van dat alt attribuut telt echter ook mee voor de toegankelijke naam van de button. De toegankelijke naam van deze button is dus "Toevoegen icoontje van een winkelwagen". En dat is niet zo handig. Omdat we in de button al de tekst "Toevoegen" hebben, is het icoontje alleen ter decoratie. Een betere oplossing is dus een leeg alt attribuut: + +```html + +``` +De toegankelijke naam is nu weer "Toevoegen", joepie! + +Tijd voor een stapje verder: De button heeft nu geen zichtbare tekst meer, maar enkel het icoontje. De toegankelijke naam is nu een lege string, en dat is niet handig. We kunnen de inhoud van het element dus niet meer gebruiken voor de toegankelijke naam. We kunnen dit nu op een aantal manieren oplossen. We beginnen met een aria attribuut wat hier speciaal voor bedoeld is: `aria-label`. + +```html + +``` + +Wanneer een element (met een rol die toegankelijke namen ondersteunt) een `aria-label` attribuut heeft wordt de inhoud van het element **volledig genegeerd**. De toegankelijke naam van deze button is nu "Toevoegen", ongeacht wat er in het element staat. Dit kan snel voor problemen zorgen. + +Stel dat we een spoedticket binnen krijgen om naast de Toevoegen knop ook een "Verwijder" knop te maken. We kopiëren snel de code van de Toevoegen knop, hangen er een andere event handler aan en passen het icoontje aan naar een prullenbak. + +```html + +``` + +We verversen de browser en het icoontje ziet er top uit en werkt ook als je er op klikt. Ship it! + +...Maar die aria-label die zien we over het hoofd: we zien die namelijk _letterlijk niet_ in de browser. Je moet dus goed opletten dat je de aria-label ook aanpast wanneer je de inhoud van een element aanpast. Een ander probleem met aria-label is dat als je browser automatisch de pagina kan vertalen, de aria-label niet mee wordt vertaald ([aria-label does not translate](https://adrianroselli.com/2019/11/aria-label-does-not-translate.html)). + +Daarom proberen we een andere oplossing, screenreader-only tekst: + +```html + +``` + +".sr-only" is geen ingebouwde standaard, maar een conventie (met bijbehorende CSS) die veel wordt gebruikt. Dit is een voorbeeld van een .sr-only CSS: + +```css +.sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border: 0; +} +``` + +Deze CSS zorgt ervoor dat de inhoud absoluut niet zichtbaar is, maar nog wel voorgelezen wordt door een screenreader. Zo kunnen we de toegankelijke naam bepalen met "gewone" tekst die ook gewoon automatisch vertaalt kan worden. Uitpluizen hoe de CSS dat doet is iets voor een ander artikel. + +Overigens is er discussie over of een dergelijke class niet ingebouwd zou moeten zijn in browsers. [Ben Myers](https://benmyers.dev/blog/native-visually-hidden/) is voor, [Scott o'Hara](https://www.scottohara.me/blog/2023/03/21/visually-hidden-hack.html) is tegen. Beide artikelen zijn het lezen waard. + +De toegankelijke naam van bovenstaande buttons wordt dus bepaald in deze volgorde: + +1. Is er een aria-label attribuut? Gebruik die. +2. Zoniet, gebruik dan de inhoud van het element. + +Dit is echter een extreem versimpelde volgorde. Om ook de rest van het 'toegankelijke naam'-algoritme te begrijpen gaan we ons voorbeeld wat complexer maken. We hebben nu twee knoppen, die ieder iets anders toevoegen: + +```html +Lekker warm
+ + +Staat je goed
+ +``` + +De toegankelijke naam van deze buttons is nu "Toevoegen". Maar dat is niet handig, want de ene button voegt een hoodie toe en de andere een pet. Als je kunt zien waar de buttons staat is dat duidelijk, maar anders heb je een probleem. Wat we hier willen is dat we de knop expliciet aan het bijbehorende product kunnen linken. Dat kan met een `aria-labelledby` attribuut: + +``` html +Lekker warm
+ + +Staat je goed
+ +``` +Met `aria-labelledby` kunnen we een ID opgeven van een ander element, en de toegankelijke naam van de button wordt dan de tekst van dat element. Net als `aria-label` wordt de inhoud van het element vervolgens genegeerd, en dat is nog wel een probleem want hoe weet een gebruiker nu dat de knop voor "Toevoegen" is? + +`aria-labelledby` lost dit op doordat je er niet slechts één ID aan kan geven, maar een lijstje. De toegankelijke naam van de button wordt dan de tekst van alle elementen die je opgeeft, gescheiden door een spatie. Als we onze buttons zelf ook een ID geven, kunnen we de tekst van de button zelf ook toevoegen: + +```html +Lekker warm
+ + +Staat je goed
+ +``` + +De toegankelijke naam van deze buttons is nu "Fronteers hoodie Toevoegen" en "Fronteers pet Toevoegen". Dit is een stuk duidelijker voor een gebruiker die niet kan zien wat er op de pagina staat. + +Maar wacht even, we hebben net geleerd dat aria-labelledby op een element de inhoud van dat element negeert. Hoe kan het dan dat de tekst van de button zelf nu wel wordt voorgelezen? Wordt dit dan geen _infinite loop_? + +Gelukkig niet! Wanneer je via `aria-labelledby` een element aanwijst, dan wordt er gekeken naar de toegankelijke naam van dat element alsof er geen aria-labelledby attribuut was. Aria-labelledby geld alleen voor de eerste stap en je komt er dus niet mee in de knoop. Daar is over nagedacht! + +Nog iets waar over nagedacht is: alle tekst die nu de toegankelijke naam vormt, is tekst in de pagina: die kan dus gewoon vertaald worden. + +Met `aria-labelledby` erbij is dit de volgorde waarop de toegankelijke naam bepaald wordt: + +1. Is er een `aria-labelledby` attribuut én is dit het eerste element waarvoor je de toegankelijke naam aan het bepalen bent? Gebruik de tekst van de elementen die je opgeeft, gescheiden door een spatie. +1. Is er een aria-label attribuut? Gebruik die. +2. Zoniet, gebruikt dan de inhoud van het element. + +## Conclusie + +Hopelijk heb je nu een beter idee waar de toegankelijke naam van elementen vandaan komt, waarom je die soms wilt veranderen en hoe je dat op een goede manier doet. + +Helaas moet ik je vertellen dat het algoritme om een toegankelijke naam te bepalen nog veel gecompliceerder is. Die complexiteit is er vooral om te voorzien in de gevallen dat bovenstaande niet werkt. Voor bepaalde type input elementen, die geen inhoud hebben, wordt er bijvoorbeeld naar het `value` gekeken. Is er geen value maar is het een button type, zoals ``? Dan krijgt het van de browser de toegankelijke naam "Submit". Textarea's zonder inhoud krijgen de toegankelijke naam van het `title` of `placeholder` attribuut. En zo zijn er nog veel meer uitzonderingen. En als aller, allerlaatste wordt het `title` attribuut van een element gebruikt. + +Dit is expliciet een laatste redmiddel voor wanneer de ontwikkelaar zijn of haar werk niet heeft gedaan. Ben je bewust bezig met toegankelijke namen? Kijk dan naar de drie opties: tekst op de pagina, aria-label en aria-labelledby. + +Wil je er meer over lezen? Hier vind je een duidelijke uitleg: [Accessible name calculation](https://www.w3.org/WAI/ARIA/apg/practices/names-and-descriptions/#name_calculation) en als je er écht in wilt duiken kan je hier de specificatie vinden: [Accessible Name and Description Computation](https://www.w3.org/TR/accname-1.2/). Maar let op, die is behoorlijk pittig. diff --git a/src/nl/leden/kilian-valkhof.md b/src/nl/leden/kilian-valkhof.md new file mode 100644 index 00000000..36bc182b --- /dev/null +++ b/src/nl/leden/kilian-valkhof.md @@ -0,0 +1,30 @@ +--- +published: true +draft: false + # Jouw naam +title: Kilian Valkhof + # Maak van de key een unieke slug (je voor en achternaam bijvoorbeeld). Hiermee wordt de Nederlandse aan de Engelse versie van deze pagina gekoppeld. +key: kilian-valkhof +date: 2020-11-10 + # Als je een afbeelding toevoegt, link dan hier naar de juiste plek: +graphic: + src: /assets/images/member-avatars/kilian-valkhof.jpg + alt: Kilian Valkhof +# Jouw functietitel +jobtitle: Productontwikkelaar +# Eventueel: jouw huidige werk- of opdrachtgever +employer: 'Polypane browser for developers' +specialties: + - accessibility + - responsive design + - product development + - developer tools + - ux design +--- + +Kilian is de maker van Polypane, een browser voor ontwikkelaars. Hij heeft een passie voor het maken van tools voor developers en designers om hun leven makkelijker en productiever te maken. + +- [Kilianvalkhof.com](https://kilianvalkhof.com) +- [Polypane.app](https://polypane.app) +- [Superposition.design](https://superposition.design) +- [Fixa11y.com](https://fixa11y.com) \ No newline at end of file