#9 Cookie Consent from Hell

submitted on by Manuel

Bad code

<body>
<header></header>
<main></main>
<footer></footer>

<div class="cookie_consent modal">
<p>We use cookies…</p>
<div class="cookie_consent__close">
<i class="fa fa-times"></i>
</div>
<div class="cookie_consent__ok">OK</div>
</div>
</body>

Issues and how to fix them

  1. The modal is not the first item on the page and focus is not on the modal when the page loads. Keyboard users have to tab through all items on the page to access the cookie consent window.
  2. A div isn’t keyboard focusable.
  3. Content inside these divs is semantically just text. Assistive technology doesn’t know that these fake buttons are actually buttons.
  4. A click event on a div triggers only on click. A click event on a button triggers on click and if the user presses the Enter or Space key.
  5. There’s no text alternative for the icon.
  6. Font Awesome advises to hide icons semantically by settings aria-hidden="true" on the <i> element.
  7. Font Awesome adds Unicode content via the ::before pseudo element. Assistive technology may announce the Unicode equivalent, which in this specific example would be “times” since fa-times is not a cross but a multiplication sign. (Please note: Talkback and VoiceOver didn’t announce anything in this example.)
  8. Bonus: it should be possible to close modals by pressing Esc.

Good code

<body>
<div class="cookie_consent modal">
<h2 class="sr-only">Cookie notice</h2>
<p>We use cookies…</p>
<button class="cookie_consent__ok">OK</button>
<button class="cookie_consent__close">
<span class="sr-only">Close notification</span>
<i class="fa fa-times" aria-hidden="true"></i>
</button>
</div>

<header></header>
<main></main>
<footer></footer>
</body>

Unfortunately, there’s no native way of hiding content only visually.
The .sr-only class makes sure that content is visually hidden but still accessible to screen reader users.

.sr-only {
position: absolute;
white-space: nowrap;
width: 1px;
height: 1px;
overflow: hidden;
border: 0;
padding: 0;
clip: rect(0 0 0 0);
clip-path: inset(50%);
margin: -1px;
}