Skip to content

Commit

Permalink
New article: prefer buttons to divs.
Browse files Browse the repository at this point in the history
  • Loading branch information
mikewest committed Dec 26, 2011
1 parent 6355eb2 commit 5756d35
Show file tree
Hide file tree
Showing 6 changed files with 191 additions and 33 deletions.
2 changes: 1 addition & 1 deletion _includes/page_header.html
@@ -1,3 +1,3 @@
<header>
<h1><a href="/"><abbr title="Web Accessibility">W<span>15</span>Y</abbr></a></h1>
<h1><a href="/"><abbr title="Web Accessibility">W<b>15</b>Y</abbr></a></h1>
</header>
3 changes: 2 additions & 1 deletion _layouts/article.html
Expand Up @@ -2,7 +2,6 @@
layout: base
---
<article class="hentry" role="main">
<h1 class="entry-title">{{ page.title }}</h1>
{% if page.youtube %}
<iframe
width="640"
Expand All @@ -13,6 +12,8 @@ <h1 class="entry-title">{{ page.title }}</h1>
allowfullscreen></iframe>
{% endif %}

<h1 class="entry-title">{{ page.title }}</h1>

{{ content }}

<address class="vcard">&mdash; <a href="/" rel="author" class="fn url">Mike West</a></address>
Expand Down
61 changes: 61 additions & 0 deletions basics/introduction-to-screen-readers/index.markdown
@@ -0,0 +1,61 @@
>> MIKE: Hello, Internet! Welcome to Web Accessibility.
Over the next fiveish minutes, I'd like to introduce you to screen readers as a first step towards talking about accessibility on the web.

A screen reader is a piece of software that takes the textual content of a web page, and renders it audibly using synthesized speech so that a person who can't see the page can nonetheless interact with it in a practical way.

A variety of readers exist on the market, including JAWS, WindowEyes, NVDA, and others. The screen reader I'll be demonstrating here is called ChromeVox. It's the accessibility system at the core of ChromeOS, and it's available as an extension to desktop Chrome. It's really easy to get up and running, and it's a great way to get familiar with the world of screenreaders.

Let's install it and start playing around.



I've got a demonstration page here, let's reload it and see how it sounds.

>> CHROMEVOX: A ChromeVox demonstration.
>> MIKE: So, entering a page, ChromeVox (and most screenreaders), will read you the title of that page in order to give you some context as to what it is you're about to see. A screen reader's user most likely can't manipulate a mouse. So, a system of keyboard shortcuts has been set up to allow them to navigate through a page. Let's use one now.
>> CHROMEVOX: Hello, World! Heading One.
>> MIKE: So it reads me "Hello, World", which is obvious, and then it tells me some additional semantic information: in this case "Heading one". It can do that because I've used semantic HTML in order to structure this document. This is an H1 element, it's a heading on the page, and the screen reader knows that. It can tell me about it to give me some extra context for the text that it's just read me.
Let's move on to the next element and see how that sounds.

>> CHROMEVOX: I'm [Beep] ChromeVox Link. Comma. the DOM Document Object Mode is all I know. Period.
>> MIKE: Interesting. ChromeVox has read something that's actually different from what I see here. Let's hop into the DOM and figure out why that is.
Well, as we can see here, I've actually wrapped individual pieces of this sentence in spans, and moved them around with relative positioning. This confuses the screen reader, because all that it has access to is the DOM. If something comes first in the DOM, it's going to get read first by the screen reader. The screen reader simply doesn't understand the CSS that you've applied. And we do- we see this happening all the time in applications and web pages. We take things from the bottom of the DOM and move them all the way to the top of the page, visually, because it makes sense there. But, given the way the DOM is structured, it can be difficult to navigate to those things just using a screen reader.

Two other things to note within the context of this sentence: first, "ChromeVox" is a link, and the screen reader read it to me differently so that I would know it's a link. It changed the pitch, and it said "link" after the word, meaning that I can use this to go somewhere else. That's nice. Also, if you look at the word "DOM", it's actually an abbreviation. And if we look at the DOM, we'll see, hey, it's an abbreviation with title "Document Object Model". This means that the screen reader takes the additional semantic information that's available within the context of HTML, and reads it to me in a way that is, uh, that's usable for someone who can't use the mouse to simply hover over this word and get the tooltip.

Let's move on to the form and see how that sounds.

>> CHROMEVOX: [Beep] What is your name? Edit text.
>> MIKE: So I hop into the form, and a couple of things happened. First, it plays a sound, a beep, that tells me I'm in an input field of some sort. Then it reads the label for that input field. And then it says "edit text", meaning that I can start typing something to interact with this form field. It's really important to ensure that all of the fields in every form that you create have labels. Otherwise the screen reader would just say "edit text", which isn't very useful. It tells me that I can type text, but doesn't give me any hint at all as to what text I should type.
Let's move on to the next field.

>> CHROMEVOX: [Beep] What is your quest? Password.
>> MIKE: This is a password field and it tells me that. Apparently quests are very secretive. In this case, it again takes extra semantic information, and renders it to me in a way that I can hear, and interact with.
>> CHROMEVOX: [Beep] What is your favorite color? Blue. List box one of two.
>> MIKE: So a list box, or a select element, is, uh, contains multiple options, and here it tells me that there are two options. If blue isn't my favorite color, for instance…
>> CHROMEVOX: Yellow. Two of two.
>> MIKE: I can choose yellow, which is, ah, a much more beautiful color. Let's hop down to the button and see how that works.
>> CHROMEVOX: Right, off you go. Button.
>> MIKE: So it tells me that it's a button, and I know that with a button, I can click on it. What I can also do is use the enter key to submit this form.
[pause]

>> MIKE: And when I submit the form, it amazingly takes me to ChromeVox in the Chrome Web Store. If you want to get involved in screen readers, and start playing around with them yourself, I'd highly recommend that you hop over to the web store, you type in "ChromeVox", and you install it. It's a one-click install, it's free, and it's really easy to get up and running. It gives you a good introduction to screen readers, and something that we can build on later on when we start talking about ARIA, custom, uh, custom widgets on a page, and a variety of other things that you'll need to think about when building accessible websites. So please, head out, download ChromeVox, and start making your sites accessible.
Thanks.
77 changes: 77 additions & 0 deletions basics/prefer-button-to-div/index.markdown
@@ -0,0 +1,77 @@
---

layout: article
title: "Prefer `button` to `div` elements"
youtube: "7fPppLXRk4A"
level: basics
tags:
- button
- div
- focus
- tabindex
- role
- aria
- screen reader

---
MIKE WEST >> Hello, Internet! Welcome to Web Accessibility.

Over the next two to three minutes, I'd like to explain why you should prefer the `button` element to the `div` element when constructing clickable widgets for your websites.

Though the two types of elements can be styled to look similarly, they do, in fact, have distinct semantics and distinct default behaviors. Because of that, it's simply more likely that you'll create an inaccessible `div` widget then it is then if you create the same widget with a `button`.

Let's take a quick look at this demo page in order to see why that's the case.

In the middle of the page you'll see a button, labelled "click me". If I tab to it, then it'll get focus, and we'll hear something distinct from the screen reader. Let's see how that works:

CHROMEVOX >> [Beep] Click me. Button.

MIKE WEST >> "Click me. Button." So the screen reader knows this is a button, and, if I use the enter key, I get a click event. This is great. This is actually exactly what we want, and it means we don't have to do any extra work at all.

Let's turn it into a `div`, just to see how that behaves.

Great, so now we have a `div`. It looks exactly the same, and if I click on it, I get exactly the same behavior.

However, there are three distinct things that I'm going to need to do in order to make this `div` behave more or less the same as the button did.

First of all, we'll note that before, the button could obtain focus: it had a nice, big purple outline. If I tab through this page, you'll see that the `textarea` gets focus, but the `div` never does. `div`s are, by default, not focusable elements. This means we have to do some extra work in order to make them focusable.

Here, we'll have to add a `tabindex` of zero. A `tabindex` of zero means that this is now a focusable element, and that it appears in the tab [order] where it, uh, where it appears in the DOM.

CHROMEVOX >> Click me.

MIKE WEST >> That's great.

First problem, solved.

Now we get to the second problem: if I hit enter in order to click on this element, absolutely nothing happens. That's a bit of a problem. You see, what I've done in JavaScript is simply hooked something up to the `click` event. A `button`, by default, automatically simulates a `click` event for me, when I hit enter.

What I'll have to do for a `div` is something completely different: I'll have to actually add another event listener on either `keydown` or `keyup` or `keypress`, depending on the exact behavior that I want.

These are things that I simply shouldn't have to think about. But I do.

Let's assume, however, that I did that work in JavaScript to make the keyboard work exactly the same as the mouse.

You'll notice one other thing if I tab to it again.

CHROMEVOX >> Click me.

MIKE WEST >> "Click me." There's no "button", right?

The screen reader doesn't understand the semantic I've created. All it sees is a `div` on the page, and a `div` by default has no semantic meaning whatsoever.

I can get around this by using an ARIA role. So if I give this `div` a `role` "button", then we can tell the screen reader to treat it as though it was a button. If I tab back to it:

CHROMEVOX >> [Beep] Click me. Button.

MIKE WEST >> Excellent. So "Click me. Button."

By adding these extra semantics, and by working around in JavaScript, I'm able to make the `div` behave the same as the `button`.

This, however, is work that I: A) often forget to do, and B) can often do incorrectly. It's also something that I don't test quite as well as I test the normal workflow for the `button`.

In this case, it's simply preferable to use a `button`. A `button` means that there's less work for me to do, and less for me to get wrong.

For more discussion of web accessibility, come visit us on the web at W one five Y dot com. That's W fifteen Y dot com.

Thanks for your time.
81 changes: 50 additions & 31 deletions static/style.css
@@ -1,46 +1,25 @@
body {
margin: 0;
padding: 38px 0 0;
padding: 0;
}

html {
background: #333 url(/static/images/texture.png);
background: #203440 url(/static/images/texture.png);
margin: 0;
padding: 0;
}

article {
width: 640px;
padding: 20px 20px;
background: rgba(255,255,255,0.8);
margin: 0 auto;
}

article h1 {
color: #222;
background: #BBB;
font: 30px/1 'Open Sans', sans-serif;
font-weight: 600;
margin: 0 0 20px;
text-rendering: optimizeLegibility;
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.2);
}

/** SITE HEADER **/
header {
background: #111;
border-bottom: 1px solid rgba(0,0,0,0.8);
position: fixed;
width: 100%;
z-index: 50;
top: 0;
left: 0;
box-shadow: -5px 3px 8px -2px rgba(0,0,0,0.8);
}

header h1 {
color: #EEE;
font: 28px/38px 'Open Sans', sans-serif;
font: 26px/1.2 'Open Sans', sans-serif;
font-weight: 700;
letter-spacing: -2px;
margin: 0 auto;
Expand All @@ -54,21 +33,61 @@ header h1 a {
text-decoration: none;
}

header h1 span {
font-size: 28px;
header h1 b {
/* Yes, `b`; the text is "stylistically offset". So there. */
color: #80D0FF;
font-weight: 700;
}

/** SITE FOOTER **/
small {
width: 642px;
padding: 0 20px;
margin: 0 auto;
display: block;
background: rgba(0,0,0,0.1);
}

/** ARTICLES **/
article {
width: 642px;
padding: 20px 20px;
background: rgba(255,255,255,0.9);
border: 1px solid rgba(0,0,0,0.9);
margin: 0 auto;
}

article h1 {
color: #203440;
font: 35px/1 'Open Sans', sans-serif;
font-weight: 600;
margin: 0.5em 0;
text-rendering: optimizeLegibility;
}

p {
font: 20px/1.4 Helvetica, Verdana, sans-serif;
color: #222;
font: 20px/1.4 'Open Sans', 'Helvetica Neue', Verdana, sans-serif;
color: #333;
}

pre {
background: #FFF;
margin: 0 -20px;
border-left: 8px solid #80D0FF;
padding: 1em 0 1em 12px;
}

code {
font: 20px Inconsolata;
font: 24px Inconsolata;
background: #FFF;
}

a {
color: #00A1FF;
article a {
color: #40687F;
text-decoration: none;
text-shadow: 0 0 2px rgba(255,255,255,0.5);
}

iframe {
box-shadow: 3px 3px 5px rgba(0,0,0,0.5);
}

0 comments on commit 5756d35

Please sign in to comment.