#26 HTMHell special: tasty buttons

submitted on by Manuel

The second HTMHell special focuses on another highly controversial pattern in front-end development:

šŸ”„ the burger button. šŸ”„

The burger button and his tasty friends (kebab, meatball and bento) usually reveal a list of links when activated. According to our studies, these buttons are highly optimized for mouse and touch users, but lack support for keyboard and screen reader users in most cases.

After less than 1 hours of research, HTMHell presents a collection of 18 different bad practices found on real websites.

Pattern 1: the unsemantic burger

<div class="burger">
<span></span>
<span></span>
<span></span>
</div>
.burger {
display: flex;
flex-direction: column;
justify-content: space-between;
width: 30px;
height: 20px;
cursor: pointer;
}

.burger span {
height: 1px;
display: block;
background: #000;
}

Issues and how to fix them

  1. The <div> element is an element of last resort, for when no other element is suitable. Use of the <div> element instead of more appropriate elements leads to poor accessibility. If you need a button, use the <button> element.
  2. 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.
  3. A div isnā€™t keyboard focusable.
  4. Thereā€™s no text label.
  5. The ā€œbuttonā€ should indicate whether the element it controls is currently expanded or collapsed (aria-expanded="false" if collapsed).
  6. Screen readers announce: Nothing.

Other variations of this pattern

The empty burger

<div class="burger"></div>

The all div burger

<div class="burger">
<div></div>
<div></div>
<div></div>
</div>

Pattern 2: The classic image burger

<img class="menu" src="menu.png">

Issues and how to fix them

  1. A click event on an img triggers only on click. A click event on a button triggers on click and if the user presses the Enter or Space key.
  2. An img isnā€™t keyboard focusable.
  3. Thereā€™s no text alternative for the image. Screen readers may announce the filename instead.
  4. The ā€œbuttonā€ should indicate whether the element it controls is currently expanded or collapsed (aria-expanded="false" if collapsed).
  5. Screen readers may announce: menu.png, image.ā€

Pattern 3: The modern image burger

<svg class="hamburger" viewBox="0 0 20 20" aria-labelledby="title">
<title>Open Navigation</title>
<g>
<rect y="3" width="20" height="2"></rect>
<rect y="9" width="20" height="2"></rect>
<rect y="15" width="20" height="2"></rect>
</g>
</svg>

Issues and how to fix them

  1. A click event on an svg triggers only on click. A click event on a button triggers on click and if the user presses the Enter or Space key.
  2. An svg isnā€™t keyboard focusable in most browsers (IE 11 is an exception).
  3. The value of aria-labelledby references elements by their id, not by tag name.
  4. The ā€œbuttonā€ should indicate whether the element it controls is currently expanded or collapsed (aria-expanded="false" if collapsed).
  5. Screen readers interpret svg elements differently. To get a consistent result the role="img" attribute should be present on the svg.
  6. Screen readers may announce: ā€œOpen Navigation, graphicā€ or ā€œOpen Navigation, group.ā€

Pattern 4: Almost a burger

<button class="navbar-toggle" type="button">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>

Issues and how to fix them

  1. Thereā€™s no text label.
  2. The ā€œbuttonā€ should indicate whether the element it controls is currently expanded or collapsed (aria-expanded="false" if collapsed).
  3. Screen readers announce: button.
<a class="menuButton"></a>

Issues and how to fix them

  1. A link without href is still not a button.
  2. If the <a> element has no href attribute, then the element represents a placeholder for where a link might otherwise have been placed.Footnote2
  3. If youā€™re adding a click event to a placeholder link, you probably donā€™t want to use a placeholder link, but an actual link with an href attribute or a <button>, depending on what's happening on click.
  4. Placeholder links aren't focusable.
  5. Thereā€™s no text label.
  6. The ā€œbuttonā€ should indicate whether the element it controls is currently expanded or collapsed (aria-expanded="false" if collapsed).
  7. Screen readers announce: probably nothing.
<a role="button" aria-label="menu" aria-expanded="false" class="burger">
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</a>
  1. Do not change native semantics, unless you really have to.
  2. If the <a> element has no href attribute, then the element represents a placeholder for where a link might otherwise have been placed.Footnote2
  3. If youā€™re adding a click event to a placeholder link, you probably donā€™t want to use a placeholder link, but an actual link with an href attribute or a <button>, depending on what's happening on click.
  4. Placeholder links aren't focusable.
  5. Screen readers may announce: ā€œmenu, collapsed, buttonā€

Pattern 7: The unsemantic burger with extra bacon

<span class="mobile-nav" aria-hidden="true">
Show nav
<span></span>
<span></span>
<span></span>
<span></span>
</span>

Issues and how to fix them

  1. Pretty much the same as Pattern 1: The unsemantic burger except that this button has a label which is good, but it also has aria-hidden="true" which means that it's completely inaccessible to screen reader users.
  2. Screen readers announce: Nothing.
<a class="toggle-link" href="javascript:">
<i class="fa fa-reorder"></i>
</a>
.fa-reorder::before {
content: "ļƒ‰";
}

Issues and how to fix them

  1. Screen readers may announce CSS generated content.Footnote1
  2. Font Awesome advises to hide icons semantically by settings aria-hidden="true" on the <i> element.
  3. The i element represents a span of text in an alternate voice or mood, or otherwise offset from the normal prose in a manner indicating a different quality of text.Footnote2 If you just want italic text, use font-style: italic; in CSS.
  4. Thereā€™s no text label.
  5. If youā€™re not sure when to use <a> or <button>, watch The Links vs. Buttons Showdown by Marcy Sutton.
  6. The ā€œbuttonā€ should indicate whether the element it controls is currently expanded or collapsed (aria-expanded="false" if collapsed).
  7. Screen readers announce: ā€œlinkā€.

Pattern 9: The ā€œI have no idea what I'm doing, let's just add some attributesā€ burger button

<div class="mega-toggle-block" tabindex="0">
<span class="mega-toggle-label" role="button" aria-expanded="false"> </span>
</div>

Issues and how to fix them

  1. The <div> element is an element of last resort, for when no other element is suitable. Use of the <div> element instead of more appropriate elements leads to poor accessibility. If you need a button, use the <button> element.
  2. 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.
  3. The div is focusable, but it has no role or label.
  4. The span tries to mimic a button, but it's not focusable and it has no label.
  5. You donā€™t need the tabindex attribute if you use a button. HTML buttons are focusable by default.
  6. Thereā€™s no text label.
  7. Screen readers may announce: ā€œgroupā€.
<a href="#menutoggle" id="menutoggle">ā˜°</a>

Issues and how to fix them

  1. A screen reader may announce this as trigram for heaven, because ā˜° is the unicode character for the trigram for heaven.
  2. The purpose of the icon is decorative, it should be hidden from screen readers. Consider adding decorative images using background properties in CSS.
  3. An anchor link is not a <button>.
  4. An anchor link should not refer to itself.
  5. If youā€™re not sure when to use <a> or <button>, watch The Links vs. Buttons Showdown by Marcy Sutton.
  6. The ā€œbuttonā€ should indicate whether the element it controls is currently expanded or collapsed (aria-expanded="false" if collapsed).
  7. Screen readers announce: ā€œtrigram for heaven, linkā€.

Pattern 11: The bento checkbox button

<div class="bento">
<input type="checkbox" id="bento">
<label for="bento"></label>
</div>
.bento label {
background-image: url(data:image/svg+xml;charset=utf-8;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnPjxwYXRoIGQ9J00zIDNoNHY0SDN6bTE0IDBoNHY0aC00em0tNyAwaDR2NGgtNHptLTcgN2g0djRIM3ptMTQgMGg0djRoLTR6bS03IDBoNHY0aC00em0tNyA3aDR2NEgzem0xNCAwaDR2NGgtNHptLTcgMGg0djRoLTR6JyBmaWxsPScjQTdBQUIyJy8+PC9zdmc+);
width: 30px;
height: 30px;
display: block;
}

.bento input {
position: absolute;
opacity: 0;
pointer-events: none;
left: -9999px;
top: -9999px;
}

Issues and how to fix them

  1. A checkbox is not a <button>.
  2. The default key events on a checkbox and a button are not the same.
  3. If youā€™re not sure when to use <a> or <button>, watch The Links vs. Buttons Showdown by Marcy Sutton.
  4. The ā€œbuttonā€ should indicate whether the element it controls is currently expanded or collapsed (aria-expanded="false" if collapsed).
  5. This ā€œbuttonā€ has no label.
  6. Screen readers may announce: ā€œunticked tickboxā€.
<ul class="offcanvas-icon">
<li>
<a href="#" class="menu-button">
<span class="dot1"></span>
<span class="dot2"></span>
<span class="dot3"></span>
<span class="dot4"></span>
<span class="dot5"></span>
<span class="dot6"></span>
<span class="dot7"></span>
<span class="dot8"></span>
<span class="dot9"></span>
</a>
</li>
</ul>

Issues and how to fix them

  1. Use <ul> to group and list related items, not as a button wrapper.
  2. An anchor link is not a <button>.
  3. CSS is quite powerful, you don't need 9 spans to display 9 dots.
  4. If youā€™re not sure when to use <a> or <button>, watch The Links vs. Buttons Showdown by Marcy Sutton.
  5. The ā€œbuttonā€ should indicate whether the element it controls is currently expanded or collapsed (aria-expanded="false" if collapsed).
  6. This ā€œbuttonā€ has no label.
  7. Screen readers may announce: ā€œlist 1 itemā€.

ā€¢ ā€¢ ā€¢

(Note: There was a click event on the link that prevented default.)

<a href="https://example.com/">ā€¢ ā€¢ ā€¢</a>

Issues and how to fix them

  1. A link is not a <button>.
  2. The default key events on a link and a button are not the same.
  3. If youā€™re not sure when to use <a> or <button>, watch The Links vs. Buttons Showdown by Marcy Sutton.
  4. The ā€œbuttonā€ should indicate whether the element it controls is currently expanded or collapsed (aria-expanded="false" if collapsed).
  5. This ā€œbuttonā€ has no label.
  6. Screen readers may announce: ā€œlink, bullet bullet bulletā€.

Pattern 14: The kebab div button

<div class="menu" title="Menu">
<i></i>
<i></i>
<i></i>
</div>

Issues and how to fix them

  1. Pretty much the same as Pattern 1: The unsemantic burger.
  2. The i element represents a span of text in an alternate voice or mood, or otherwise offset from the normal prose in a manner indicating a different quality of text.Footnote2 If you just want italic text, use font-style: italic; in CSS.
  3. Screen readers may announce: nothing.

Pattern 15: The hamburger

<button class="nav__toggle-button" aria-label="Hamburger Menu">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path d="M0 0h24v24H0z" fill="none"></path>
<path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z" fill="currentColor"></path>
</svg>
</button>

Issues and how to fix them

  1. Not as bad as all the others, but the term ā€œHamburgerā€ might confuse users.
  2. The ā€œbuttonā€ should indicate whether the element it controls is currently expanded or collapsed (aria-expanded="false" if collapsed).
  3. Screen readers may announce: ā€œbutton, Hamburger Menuā€.

Pattern 16: The chatty burger button

<button aria-label="All Company expand to see list of Company products and services" aria-expanded="false"></button>

Issues and how to fix them

  1. Not as bad as all the others, but the label is too long. Keep it short and simple.
  2. Screen readers may announce: ā€œbutton, All Company expand to see list of Company products and services, expandedā€.

Alternatives

Solution 1: A button with visible text and no icon.

<button type="button" aria-expanded="false">
Menu
</button>

  1. Text only: easy to implement and comprehensible.
  2. Screen readers may announce: Menu, buttonā€.

Solution 2: A button with visible text and only visually accessible icon.

<button type="button" aria-expanded="false">
<svg aria-hidden="true"> ā€¦ </svg>
Menu
</button>

  1. If you want to use an icon, hide it from screen readers by wrapping it in a span with aria-hidden="true".
  2. Screen readers may announce: Menu, buttonā€.

Solution 3: A button with hidden text and only visually accessible icon.

<button type="button" aria-expanded="false">
<span class="sr-only">Menu</span>
<svg aria-hidden="true"> ā€¦ </svg>
</button>
.sr-only {
position: absolute;
white-space: nowrap;
width: 1px;
height: 1px;
overflow: hidden;
border: 0;
padding: 0;
clip-path: inset(50%);
margin: -1px;
}

  1. 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.
  2. Screen readers may announce: Menu, buttonā€.

Solution 4: A button with accessible text and only visually accessible icon.

<button type="button" aria-label="Menu" aria-expanded="false">
<svg aria-hidden="true"> ā€¦ </svg>
</button>

  1. If you donā€™t want to show text on screen, provide a text alternative for your icon or SVG by adding aria-label to the button.
  2. Screen readers may announce: Menu, buttonā€.

Wanna learn accessibility testing?

Are you interested in learning how to discover these accessibility issues and a lot more? Then join me for a Smashing Magazine workshop starting on November 4th.

Deep Dive On Accessibility Testing
Workshop, 5Ɨ2.5h + Q&A
Thu & Fri, November 4ā€“18 202109:00 ā€“ 11:30 AM PT (Pacific, US) ā€¢ 18:00 ā€“ 20:30 CET (Europe)

Use this link for a special -15% discount.