The following explanations are mandatory knowledge for any Front End Developer working on a project that has to fulfil the accessibility guidelines1 set by the W3C2 and enforced by the UK Government Standards3 or the US Section 508 4standards.
Accessibility means making the web site accessible for everybody, regardless of software, hardware or mean of web access. Surfers can use web sites with browsers, text browsers, switch access or screen readers. An accessible web site has to ensure that each of these ways can be used to reach the same goal.
This does not mean that the web site has to be bland and boring, it means that the HTML has to be good and understandable for even the most basic means; more visual experience or usability enhancing elements get added later.
This is nothing new, all it takes is some more discipline of the HTML scripter.
HTML that is not well-formed will cause a lot of assistive technology to choke. That is why the HTML developed has to adhere to one of the HTML standards defined by the W3C. This can be bland HTML 4.05 or even 3.26 if you need to cater older browsers with as visually appealing results as current ones, or xHTML7, if you want your HTML to be readable and parseable for XML Software.
In any case, the HTML needs to be validated either via the Homesite validator or the W3C validator8.
By defining the correct DOCTYPE9 you tell the browser software what this document is and how it should treat it. Depending on the DOCTYPE browsers display HTML either in Quirks or in Standard mode10. Quirks mode simulates the flaws in rendering of older browsers even in the new ones, Standard mode forces the correct W3C compliant display. In the case of Internet Explorer this especially means the W3C box model11 will be properly displayed12.
To ensure standards compliant rendering on IE6, Mozilla and Opera, use the following DOCTYPES:
<!DOCTYPE HTML PUBLIC "//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<!DOCTYPE html PUBLIC "//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1transitional.dtd">
The next thing you need to teach the browser, is how to deal with special characters and define the language of the document. This is necessary for the display of special characters in languages like German, French, Spanish or Scandinavian Languages. The Definition of the language helps screen reader users to select a different voice to read out the text with the correct pronunciation.
The display of the characters is defined in the character encoding13. When dealing with European or English pages we can use the ISO-8859-1 encoding, multinational sites and HTML documents necessary to be XML compliant without CDATA elements should use UTF-8.
The last thing the browser needs to know is how the text will be read, either from left to right (ltr) or from right to left (rtl).
<html dir="ltr" xml:lang="en" lang="en"> <head> <meta httpequiv="ContentType" content="text/html; charset=iso88591" /> </head>
Valid (x)HTML needs to have all tags in lower case! There are no exceptions. Under no circumstances mix the cases.
In HTML 4.0 you need to ensure all tags are nested correctly, in xHTML you additionally need to close all tags.
To ensure backward compatibility with older browsers, do not close tags in themselves without a space, f.e. <hr/> could make older browsers to skip the tag, whereas <hr /> will be rendered as a horizontal rule.
<DIV class=headline>How to mess up:</DIV> <UL> <li>mix upper and lower case</LI> <li>use HTML elements for another purpose</LI> <ul> <li>nest incorrectly</li> <li>don't think of HTML as a node tree</li> </ul> <LI>Mix display, markup and content </ul>
<h1>How to make HTML understandable</h1> <ul class="goodHTMLinfo"> <li>Lowercase all tags</li> <li>Ensure your HTML is a valid document <ul> <li>Nest correctly</li> <li>Try to keep a clean, parseable node tree</li> </ul> </li> <li>Keep markup, visual appearance and content separate.</li> </ul>
Attributes in valid HTML need to be lowercase and embedded in quotation marks.
Theoretically these could be also inverted commas (') but general practise is to use the code quotation mark ("). Some attributes are not a name-value pair, like "selected", "noshade" or "checked". In xHTML, these have to be turned into one.
<a HREF=Javascript:void() onClick=popup('annoy.html')>Click here</a> <input TYPE=checkbox VALUE="test" checked>Are you OK with popups?
<a href="annoy.html" onclick="popup(this.href);return false"> Click here to open in a popup</a> <input type="checkbox" id="popcb" value="test" checked="checked" /> <label for="popcb">Are you OK with popups?</label>
When HTML was invented, it was meant to be a mean of taking a text and cutting it up into logical elements; HTML is there to describe what a certain text element is.
That is all there is to it. By following these logical definitions, we can make our markup scripting life a lot easier.
The headline tags, h1 to h6, are to be used to tell the browser what is a headline. Screen reader software allows users to jump from headline to headline to scan through a text faster; search engines prefer headlines to scan and compare texts to their search matches.
So any time a text has a headline, use an h tag, not a div with an id or class or an image.
Use headlines consistently, the main page headline is h1, one below is h2, another below is h3, one on the same informational level as the second one is h2 again.
Do not nest headlines incorrectly.
Paragraphs are parts of a text followed by a break. In HTML, use the P tag to mark them. If possible, try to refrain from using line breaks (BR) instead of paragraph tags. Reason for this is that by using a P, you
The quick brown fox jumped over the lazy dog, not realising that the dog was just pretending to sleep. The quick brown fox jumped over the lazy dog, not realising that the dog was just pretending to sleep.
The quick brown fox jumped over the lazy dog, not realising that the dog was just pretending to sleep. The quick brown fox jumped over the lazy dog, not realising that the dog was just pretending to sleep.
function remove(){ parentObj=document.getElementById('demo2'); todel=parentObj.getElementsByTagName("p")[1]. firstChild; parentObj.getElementsByTagName("p")[1]. removeChild(todel); } function replace(){ parentObj=document.getElementById('demo2'); txt=parentObj.getElementsByTagName("p")[0]. firstChild.nodeValue.replace('fox','cat'); parentObj.getElementsByTagName("p")[0].firstChild. nodeValue=txt; }
p{ margin:.5em 0 0 0; text-indent:1em; text-align:justify; }
<div id="demo1"> The quick brown fox jumped over the lazy dog, not realising that the dog was just pretending to sleep. The quick brown fox jumped over the lazy dog, not realising that the dog was just pretending to sleep. <br /><br /> The quick brown fox jumped over the lazy dog, not realising that the dog was just pretending to sleep. The quick brown fox jumped over the lazy dog, not realising that the dog was just pretending to sleep. <br /><br /> </div> <div id="demo2"> <p> The quick brown fox jumped over the lazy dog, not realising that the dog was just pretending to sleep. The quick brown fox jumped over the lazy dog, not realising that the dog was just pretending to sleep. </p> <p> The quick brown fox jumped over the lazy dog, not realising that the dog was just pretending to sleep. The quick brown fox jumped over the lazy dog, not realising that the dog was just pretending to sleep. </p> </div>
Lists are very handy when you want to give information in a very compact format or when you need to ensure that elements are separated from another without being long enough to be own paragraphs.
A perfect example of a list is a site navigation. As the accessibility standards require links to be separated by something different than whitespace, use a list to create the navigation. With the correct stylesheet, you can make the navigation look the same, but the markup is perfectly readable for screen readers and CSS-unaware browsers.
Under no circumstance use UL to indent a text, this should be done with CSS instead.
<div id="nav"> <ul> <li><a href="index.html">Home</a></li> <li><a href="nav1.html"> <strong>Element1</strong> </a></li> <li><a href="nav2.html">Element2</a></li> <li><a href="nav3.html">Element3</a></li> <li><a href="nav4.html">Element4</a></li> <li><a href="nav5.html">Element5</a></li> </ul> </div>
#nav ul{ list-style-type:none; margin:0; padding:0; text-indent:0; width:12em; border-bottom:1px solid #000; } #nav li{ text-indent:0; border:1px solid #000; border-bottom:none; } #nav li a{ color:#000; display:block; margin:0px; width:100%; text-decoration:none; font-family:sans-serif; } #nav li a strong,#nav li a:hover{ color:#fff; font-weight:normal; display:block; margin:0px; width:100%; background:#369; }
Links are what makes the web what it is, use them to link documents and to send the surfer to a target on the page.
Links to targets in the page can and should be used as skip links to allow screen reader users to jump over tedious elements of the page.
Make sure to only add links that will work under any circumstance, do not link Javascripts directly.
When using links next to another, make sure to add a different character so separate them than whitespace. One common standard is the pipe character (|).
Each link can get a title attribute explaining in more detail where the link leads to.
<a href="test.doc" title="Test results document in Microsoft Word format, 80 Kilobytes">Download test.doc</a>
<a href="#content">Skip to content</a> <div id="nav"> <ul> <li><a href="index.html">Home</a></li> <li><a href="nav1.html"><strong>Element1</strong> </a></li> <li><a href="nav2.html">Element2</a></li> <li><a href="nav3.html">Element3</a></li> <li><a href="nav4.html">Element4</a></li> <li><a href="nav5.html">Element5</a></li> </ul> </div> <a href="#content">Content starts here</a>
<a href="#explanations" onclick="trigger('exp');return false;"> Click here to show/hide explanations</a> <div id="exp"><h1><a name="#explanations">Explanations</a></h1> [...]</div>
If for any reason the Javascript function trigger() should fail, the browser simply jumps to the target in the explanations DIV.
<a href="annoy.html" onclick="popup(this.href);return false"> Click here to open in a popup</a>
Should Javascript not be available, the file annoy.html will be opened in the same browser window, if Javascript is available, a popup window will appear.
One of the biggest concerns of making web sites accessible for everybody is the question how to make a blind person get the same experience from an image than a sighted one. The answer is alternative texts, titles and, if necessary, long descriptions.
You have to set an ALT attribute in each image, and, to describe it further, a TITLE attribute. If the size of the image is known, it does not hurt to add a width and height attribute to help the browser render faster.
Longdescription is hardly necessary, but sometimes there are images that need it.
The ALT attribute of the IMG tag is there to be a text replacement, should the image not be available or should images be turned off or not at all in the browser specifications. The TITLE attribute is there to give detailed information of what the image is about. For years browsers have rendered the ALT information as a tooltip popup when you hovered your mouse over the image. This is actually a bug, as this is what title is for. IE still has that flaw, but overwrites the ALT tooltip when there is a TITLE attribute available. Opera and Mozilla do it correctly.
<img src="footlogo.gif" width="115" height="26" alt="Visit Britain Logo" title="Visit Britain, your official guide to Britain" border="0" />
Although most of the time you won't have to write these texts, just remember one tip should you want to do this: A good alt text simply states what the image is, like "sunset over an island", whereas a good title explains a bit more and conveys some emotions. "Picture of a setting sun over an island, you can see the palm trees dark in front of a red and yellow sun. The picture shows that it warm and beautiful there". To test if your text is good, imagine someone reading it out to you over the phone. Would you be able to envision what the image is about and would you get a "feeling" for it?
Screen furniture are images that are nice to look at, but don't have any real meaning for the layout or the content of the document. These can be the infamous spacer GIFs for table layouts or just rounded corners. In any case they are just playing a small role in the visual layout of the page.
Do not give these images any title and do not give these images any alternative text.
Simply add a blank alt attribute alt=""
in them. This will make
text browsers and screen readers blank out the image. Not giving the image an
alt attribute would display/read out the filename to the user.
When you have an image that is sliced up into different parts, probably as different image formats made more sense, do not repeat the same alt and title for each of them, as that would repeat this info for screen readers and text browsers. Simply add all the information to the first image and treat the rest as screen furniture.
For really complex images (schemas, charts), you can use the longdesc attribute to link the image to a very basic HTML document explaining what it is about.
Longdesc is not properly supported by browsers to date. That's the reason why some designers that need this technique started to add a textlink called [D] directly after the image, that links to the same document. This technique is quite known in the screen reader user world by now, but not really necessary.
<img src="footlogo.gif" width="115" height="26" alt="Visit Britain Logo" longdesc="logoinfo.html" title="Visit Britain, your official guide to Britain" border="0" /> <a href="logoinfo.html">[D]</a>
Tables are what you need to learn to see from a totally new angle when you deal with accessible web sites. Due to browser bugs and layouts with rules of print design being used in web design, tables have been abused as layout techniques for a long time now. This is by far not over as a lot of designs cannot be achieved completely by using Cascading Stylesheets.
This is why you need to differentiate between Data Tables (the actual tables) and Display Tables (the hack we use to work around browser problems).
Generally a table is a matrix of data which shows a connection between some headers and rows or cells of content.
For the sighted user, it is a very efficient way of display and is pretty self-explanatory, for a blind user it can be a nightmare, if is not done correctly.
Time | Task | Real happening |
---|---|---|
8:00 - 9.00 AM | Stand up, have some food | Overslept, re-heated coffee |
9:00 - 10.00 AM | Travel to the office | Tube got stuck, waited for 40 minutes without any explanation |
10:00 - 11.00 AM | Check emails | I'm still in the tube, swearing silently |
12:00 - 1.00 PM | Phone Conference | Arrived at the office. |
1.00 - 1.30 PM | Write Minutes into an email, define action items. | Tried to find the people of the phone conference, only to find out that the conference was cancelled. |
1.30 - 2.00 PM | Have a healthy lunch break, get some sun and food. | After realising that the good food places around the office are closed, grabbed a sandwich and ate it while being rained upon. |
This is pretty understandable for a sighted user. A blind user on the other hand would get the same information like this:
My Day Time Task Real happening 8:00 - 9.00 AM Stand up, have some food Overslept, re-heated coffee 9:00 - 10.00 AM Travel to the office Tube got stuck, waited for 40 minutes without any explanation 10:00 - 11.00 AM Check emails I'm still in the tube, swearing silently 12:00 - 1.00 PM Phone Conference Arrived at the office. 1.00 - 1.30 PM Write Minutes into an email, define action items. Tried to find the people of the phone conference, only to find out that the conference was cancelled. 1.30 - 2.00 PM Have a healthy lunch break, get some sun and food. After realising that the good food places around the office are closed, grabbed a sandwich and ate it while being rained upon.
This was the reason why some new HTML elements and attributes had to be introduced to tell screen readers what the connection between the headers and the cells is.
To create a table that is understandable for screen readers, you need to add some new tags and attributes. First up, the summary. This is an attribute of the table tag, which gets read out to the user before the real data begins. The user also has the option to skip the table after he hears the summary.
Next you can add a caption to show sighted users also what the table is about.
Unlike the commonly known Layout or Display Tables, a Data Table needs TH elements next, these are the table headers, the elements that explain what the other table cells under or next to these headers are about.
To link these headers to the TD elements they explain, you can use two methods.
The easiest method is adding a SCOPE attribute to the TH that describes which cells are connected to it. SCOPE can have the following values:
In day to day projects we will only need col and row, complex tables might need colgroup and rowgroup though (like a bill could need THEAD TBODY and TFOOTER).
<table summary="What I did today" border="1"> <caption>My Day</caption> <tr> <th scope="col">Time</th> <th scope="col">Task</th> <th scope="col">Real happening</th> </tr> <tr> <th scope="row">8:00 9.00 AM</th> <td>Stand up, have some food</td> <td>Overslept, reheated coffee</td> </tr> <tr> <th scope="row">9:00 10.00 AM</th> <td>Travel to the office</td> <td>Tube got stuck, waited for 40 minutes without any explanation</td> </tr> <tr> <th scope="row">10:00 11.00 AM</th> <td>Check emails</td> <td>I'm still in the tube, swearing silently</td> </tr> <tr> <th scope="row">12:00 1.00 PM</th> <td>Phone Conference</td> <td>Arrived at the office.</td> </tr> <tr> <th scope="row">1.00 1.30 PM</th> <td>Write Minutes into an email, define action items. </td> <td>Tried to find the people of the phone conference, only to find out that the conference was cancelled. </td> </tr> <tr> <th scope="row">1.30 2.00 PM</th> <td>Have a healthy lunch break, get some sun and food. </td> <td>After realising that the good food places around the office are closed, grabbed a sandwich and ate it while being rained upon.</td> </tr> </table>
SCOPE is the easier way, but some older screen readers won't be able to cope with it. A more complex, but more reliable way is to use ID and headers, each TH gets and ID and each TD gets a HEADERS attribute that lists the IDs this cell should get connected to.
<table summary="What I did today" border="1"> <caption>My Day</caption> <tr> <th>Time</th> <th id="task">Task</th> <th id="real">Real happening</th> </tr> <tr> <th id="time8to9">8:00 9.00 AM</th> <td headers="task time8to9">Stand up, have some food</td> <td headers="real time8to9">Overslept, reheated coffee</td> </tr> <tr> <th id="time9to10">9:00 10.00 AM</th> <td headers="task time9to10">Travel to the office</td> <td headers="task time9to10">Tube got stuck, waited for 40 minutes without any explanation</td> </tr> <tr> <th id="time10to11">10:00 11.00 AM</th> <td headers="task time10to11">Check emails</td> <td headers="task time10to11">I'm still in the tube, swearing silently</td> </tr> <tr> <th id="time12to13">12:00 1.00 PM</th> <td headers="task time12to13">Phone Conference</td> <td headers="task time12to13">Arrived at the office.</td> </tr> <tr> <th id="time13to1330">1.00 1.30 PM</th> <td headers="task time13to1330">Write Minutes into an email, define action items.</td> <td headers="task time13to1330">Tried to find the people of the phone conference, only to find out that the conference was cancelled.</td> </tr> <tr> <th id="time1330to14">1.30 2.00 PM</th> <td headers="task time1330to14">Have a healthy lunch break, get some sun and food.</td> <td headers="task time1330to14">After realising that the good food places around the office are closed, grabbed a sandwich and ate it while being rained upon.</td> </tr> </table>
You can use two more attributes to enhance a table for screen readers, ABBR and AXIS.
abbr="3 medal winners"
which will
speed up the readout of the table immensely. ABBR can also be added to
each TD.<table summary="What I did today" border="1"> <caption>My Day</caption> <tr> <th>Time</th> <th id="task">Task</th> <th id="real">Real happening</th> </tr> <tr> <th abbr="before 9" id="time8to9">8:00 9.00 AM</th> <td headers="task time8to9">Stand up, have some food</td> <td headers="real time8to9">Overslept, reheated coffee</td> </tr> <tr> <th abbr="before 10" id="time9to10">9:00 10.00 AM</th> <td headers="task time9to10">Travel to the office</td> <td abbr="tube failure" headers="task time9to10">Tube got stuck, waited for 40 minutes without any explanation</td> </tr> <tr> <th abbr="before 11" id="time10to11">10:00 11.00 AM</th> <td headers="task time10to11">Check emails</td> <td abbr="tube failure" headers="task time10to11">I'm still in the tube, swearing silently</td> </tr> <tr> <th abbr="before1" id="time12to13">12:00 1.00 PM</th> <td headers="task time12to13">Phone Conference</td> <td headers="task time12to13">Arrived at the office.</td> </tr> <tr> <th abbr="before 1 30" id="time13to1330">1.00 1.30 PM</th> <td abbr="sum up conference" headers="task time13to1330">Write Minutes into an email, define action items.</td> <td abbr="conference was cancelled" headers="task time13to1330"> Tried to find the people of the phone conference, only to find out that the conference was cancelled.</td> </tr> <tr> <th abbr="before 2" id="time1330to14">1.30 2.00 PM</th> <td abbr="lunchbreak" headers="task time1330to14">Have a healthy lunch break, get some sun and food.</td> <td abbr="fast snack" headers="task time1330to14">After realising that the good food places around the office are closed, grabbed a sandwich and ate it while being rained upon.</td> </tr> </table>
Display or Layout tables are a lot easier, all you need to make sure is that you
When you use a layout table make sure that the content of it also makes sense when you read the table without the layout it produces. You can simulate that either via a text browser (LYNX) or via the "disable tables" option in Opera.
[...] | [...] | [...] |
[...] | ||
[...] | [...] | [...] |
[...] |
<table width="500" border="1" cellpadding="0" cellspacing="0"> <tr> <td width="400">[...]</td> <td width="50">[...]</td> <td width="50">[...]</td> </tr> <tr> <td colspan="3">[...]</td> </tr> <tr> <td rowspan="2">[...]</td> <td>[...]</td> <td>[...]</td> </tr> <tr> <td colspan="2">[...]</td> </tr> </table>
If you create layouts via tables, be aware of the following: