Make Flash accessible to screen readers in transparent window mode

The detour around flash for accessibility

Yahoo! Tech’s home page features a flash-based media space that highlights stories, comparisons, buying guides, blog posts, and more. Making this accessible required a bit of trial and error, but the solution was simple and can be used by sites everywhere.

Step 1. Inserting the flash object

The site uses the Unobtrusive Flash Object script by Bobby van der Sluis. This script checks to see if the user has JavaScript enabled and the correct version of Flash in their browser. If so, it inserts the code required to display the movie. If the user doesn’t have the requirements, a default set of information is presented.

This script cures the validation errors caused by the normal flash insertion code. Theoretically, it would also allow you to provide good, accessible content to those not using JavaScript and Flash enabled browsers, i.e. screen readers and search robots.

Window Mode Transparency conflict

However, we had an issue with the flash movie conflicting with a DHTML drop down menu. The flash movie wanted to have the highest z-index and thus sat on top of the menu. To cure this problem, we added the attribute wmode:transparent. This tells the flash movie: your window mode is transparent, you are not the boss, go sit in the back and let others take center stage.

This cured the overlapping issues but negated the accessibility features that we had hoped for. User testing with a screen reader was disheartening. Screen readers ignore flash movies with window mode transparent. They want to do what’s best for the user and ignore the little guy in the back corner.

We began searching for answers on the flash and accessibility forums and couldn’t find a way to get screen readers to read a flash movie with wmode:transparent. It simply isn’t possible at this time.

Step 2. Time for a detour

The U.F.O. enabled page features a div with default text. This is where we originally duplicated the content being fed via xml to the flash movie. Our hope was that the screen readers would ignore the flash and read the HTML content in this div. When this wasn’t possible, we literally thought outside the box.

The U.F.O. script uses visibility:hidden to hide the default box. We tried using text-indent and negative margins instead, but it still was not available to the screen reader.

The default div now has your standard non-optimized warning text: “For the best experience, please enable JavasScript and download the latest version of Flash….

screen with css disabled - both versions viewable
We then created a new div (id=”alternatecontent”) that features the content from the flash movie. It is pushed off screen by using absolute positioning. This hides the duplicated content from the visual design while providing the content to those without the visual abilities.

We’re satisfying two audiences with just a little extra code. Add the extra div for your screen reader audience (…and search engines!) when using wmode:transparent in your Flash movie. You’ll create valid, visually dynamic, and accessible pages.

Listen to the Yahoo! Tech media space as read by a screen reader (.mp3)

Image replacement and screenreaders

Ok kids, if you use image replacement to create super-cool rollover buttons, raise your hands. Good. Now, keep your hands raised if you put title attributes on the links to give added information. Great! What is the text inside the link? Keep your hands raised if you repeated your title attribute in the link text.

Congratulations, you’ve probably done some usability testing with an actual screen reader.

For those who put your hands down; here’s the deal-eeo. Screenreaders ignore title attributes by default. Sucks… I know. I’ve been adding really juicy title attributes for usability and they’re being ignored!

Go ahead and duplicate your text

I was doing some user-testing today with Victor Tsaran, the Accessibility Project Manager at Yahoo! He came across a button with link text that was the same as the image. He said, “what’s this going to do?” It was a simple thing like “more info”… But the title attribute said “Visit Joe’s Web Site for more information.” That, he suggested, should have been the link text.

The link text is hidden from the visual users and the title attribute is hidden from the screen readers; so duplicating the information isn’t a bad thing. If you find yourself putting good information in a title attribute for a link that is using image replacement, duplicate the content in the link. It’s that simple. Now, put your hands down, it’s starting to smell musky around here.

View your site in shades of grey

Mike Cherim just announced the beta version of his new contrast-testing site. Graybit.com allows you to see what your site looks like when colors are removed.

What does it answer?

  • Is your site still usable?
  • Is there enough contrast?
  • Are you telling people to click on the cute red button?
  • Do your forms use color to distinguish required inputs?

Using vertical-align for images and buttons

I’m working on a basic search form and the visual design requires a graphic button instead of the browser-generated input. I’m using the button tag instead of an input type=”submit”. While putting the page together, I had a nagging issue with the button not aligning with the label and input. I tried various combinations of margins, negative-margins, padding, and even floated the elements. All of these techniques eventually worked, but the were too klunky and I knew there had to be a better way.

I remembered the vertical-align:middle style while working on a footer paragraph that included inline links and RSS buttons. I tried it with the submit button and it also worked perfectly. I’ve tested this in FF 1.5 and IE6. I have not tested it in Safari yet.

Code Examples

CSS:

form#foo button {vertical-align:middle; border:none; padding:0; background:none; cursor:pointer; *cursor:hand; /*alternate cursor for IE*/}

HTML

...

Resources

The perfect FAQ page ! – by Thierry Koblentz

— This was originally published on www.tjkdesign.com. Visit the original site for updated code and to see a working copy of the script. Thierry has created a Dreamweaver plugin to make this super-easy to add to your site!

This is about using a Definition List and the DOM to create a nice FAQ page where clicking on the DTs (the questions) “toggles” the associated DDs (the answers).

Note: If you’re already using this solution, please check your version number (this is version 1.5.4). Before you download the newest version I suggest to go through the entire article again (since a few things have changed).

This is what it does:

Open AllClose All

Question 1?
The vitality of conceptual synergies is of supreme importance exploiting the productive lifecycle working through a top-down, bottom-up approach. To focus on improvement, not cost, from binary cause and effect to complex patterns, while those at the coal face don’t have sufficient view of the overall goals.
Question 2?
To focus on improvement, not cost, from binary cause and effect to complex patterns, while those at the coal face don’t have sufficient view of the overall goals. To ensure that non-operating cash outflows are assessed.
Question 3?
The vitality of conceptual synergies is of supreme importance exploiting the productive lifecycle working through a top-down, bottom-up approach. To focus on improvement, not cost, from binary cause and effect to complex patterns, while those at the coal face don’t have sufficient view of the overall goals. To ensure that non-operating cash outflows are assessed. The vitality of conceptual synergies is of supreme importance exploiting the productive lifecycle working through a top-down, bottom-up approach.
Question 4?
The vitality of conceptual synergies is of supreme importance exploiting the productive lifecycle working through a top-down, bottom-up approach. To ensure that non-operating cash outflows are assessed.
Question 5?
The vitality of conceptual synergies is of supreme importance exploiting the productive lifecycle working through a top-down, bottom-up approach. To focus on improvement, not cost, from binary cause and effect to complex patterns, while those at the coal face don’t have sufficient view of the overall goals. To ensure that non-operating cash outflows are assessed.

The main advantages of the basic technique (related to the DL):

  • It uses semantic markup.
  • It degrades nicely (hidden elements are visible in script-disabled UAs).
  • DTs do not appear as links without script support.
  • It does not use inline event attribute (onclick()).
  • It does not require A elements in the markup.
  • It is screen-readers “friendly”.
  • It is keyboard “friendly”.
  • It is IE Mac compatible.
  • It relies on one single hook.
  • It allows the author to add/move/delete DT/DD pairs easily (there is no variable in the script to edit and there are no class or ID to include nor change).
  • It is “powered” by a very light script (3Kb).

About the “Show All/Hide All” “links”:

  • they let the user expand all answers at once, so it is possible to search the document.
  • they are hidden from Javascript-challenged browsers.
  • they can be “Named Anchors”, images or SPANs (actually they can be any inline elements or any other elements styled as inline).

This is more or less a plug-and-play solution (script and stylesheets are at the bottom of this page).
You’ll need to:

  1. Create a Definition List (do not use more than one DD per DT.); the markup for the one above looks like this:

    Question 1
    The vitality of conceptual synergies...
    Question 2
    To focus on improvement, not cost, ...
    Question 3
    The vitality of conceptual synergies...
    Question 4
    The vitality of conceptual synergies...

  2. Assign a specific ID to your DL:

    <dl id="TJK_DL" />
  3. Download this ZIP File (3Kb) and unzip its content in the same directory as your FAQ page.
  4. In your FAQ page, right above the closing headtag cut and paste the following:
    <script type="text/javascript" src="TJK_ToggleDL/TJK_ToggleDL.js"></script>
  5. Call the script, for example using:

    <body onload="TJK_ToggleDL()">

    Note: In case you want to add multiple onload handlers to a page, make sure to read executing JavaScript on page load.

  6. In order to use the “Show All” / “Hide All” feature, you will need to create 2 named anchors with specific IDs (TJK_ToggleON and TJK_ToggleOFF). Dreamweaver users can take advantage of the “Named Anchor” icon in the toolbar to easily create the required markup. Dreamweaver will plug the name attribute as well, but that’s OK, you can either delete it or ignore it.
    This is the markup I’m using in this page:

    <a id="TJK_ToggleON">Open All<<a id="TJK_ToggleOFF">Close All</a>

    Note: adjacent anchors are confusing in text-browsers.

    important noteYou can also replace these Named Anchors with other inline elements, for example SPAN or IMG (yes, images). Just make sure to set the proper IDs.

  7. Because we want to hide these “links” from script-challenged UAs, you need to include the following rule somewhere inside your stylesheet:
    #TJK_ToggleON,#TJK_ToggleOFF {display:none}

    Note: You can also use a style element to include this rule in the head of your document (your FAQ page).

You’re done!

Feel free to edit the rules in the CSS file to fit your needs.

important noteNote: in case your questions are more than one line long, you may want to change this: “background:0 50%” to this: “background:0 0” and add “display:block” to the #TJK_DL dt a {} rule (to avoid any “wrapping”).

For the curious

TJK_ToggleDL.js


// Copyright 2006 | Thierry Koblentz - www.TJKDesign.com All Rights reserved
// TJK_ToggleDL() Version 1.5.4 report bugs or errors to thierry@tjkdesign.com
if (document.getElementById && document.getElementsByTagName){
document.write("<link href=\"TJK_ToggleDL/TJK_ToggleDL.css\" type=\"text/css\" rel=\"stylesheet\" />")
document.write("<link href=\"TJK_ToggleDL/TJK_ToggleDL_ie5mac.css\" type=\"text/css\" rel=\"stylesheet\" />")
}
function TJK_doToggleDL(x){
var zDD=document.getElementById('TJK_DL').getElementsByTagName('dd');
var zDT=document.getElementById('TJK_DL').getElementsByTagName('dt');
zDD[x].className=(zDD[x].className=='hideDD')?'showDD':'hideDD';
zDT[x].className=(zDT[x].className=='DTplus')?'DTminus':'DTplus';
}
function TJK_ToggleDLopen(){//we open all of them
var zDD=document.getElementById('TJK_DL').getElementsByTagName('dd');
var zDT=document.getElementById('TJK_DL').getElementsByTagName('dt');
for(var i=0;i<zDT.length;i++){
zDD[i].className='showDD';
zDT[i].className='DTminus';
}
return false;
}
function TJK_ToggleDLclose(){//we close all of them
var zDD=document.getElementById('TJK_DL').getElementsByTagName('dd');
var zDT=document.getElementById('TJK_DL').getElementsByTagName('dt');
for(var i=0;i<zDT.length;i++){
zDD[i].className='hideDD';
zDT[i].className='DTplus';
}
return false;
}
function TJK_ToggleDL(){
if (document.getElementById && document.getElementsByTagName){
var zDT=document.getElementById('TJK_DL').getElementsByTagName('dt;
var zDD=document.getElementById('TJK_DL').getElementsByTagName('dd');
var ToggleON = document.getElementById('TJK_ToggleON');
var ToggleOFF = document.getElementById('TJK_ToggleOFF');
if (ToggleON && ToggleOFF){
ToggleON.onclick = TJK_ToggleDLopen;
ToggleON.title = "Show all answers";
ToggleON.href = "#";
ToggleOFF.onclick = TJK_ToggleDLclose;
ToggleOFF.title = "Hide all answers";
ToggleOFF.href = "#";
}
for(var i=0;i<zDT.length;i++){
var zContent = zDT[i].innerHTML;
var zHref = "<a href='#' onclick=\"TJK_doToggleDL("+i+");return false\" title='Show/hide the answer'>";
zDT[i].innerHTML = zHref + zContent + "</a>";
zDD[i].className='hideDD';
zDT[i].className='DTplus';
}
}
}

TJK_ToggleDL.css


/* "Show All" + "Hide All" links */
#TJK_ToggleON,#TJK_ToggleOFF {border:1px solid #333;padding:0 5px;margin-right:5px}
/* zeroing out padding and margin */
#TJK_DL dd,#TJK_DL dt {margin:0;padding:0}
/* margin for the DTs (shorthand) */
#TJK_DL dt {margin:7px 0}
/* image and left padding for DDs */
#TJK_DL dd {background:url(answer.gif) no-repeat;padding-left:55px}
/* styling all anchors in the DTs */
#TJK_DL dt a {background:0 50% no-repeat;padding-left:32px;color:#000;text-decoration:none}
#TJK_DL dt a:visited {color:#666}
#TJK_DL dt a:visited:hover, #TJK_DL dt a:hover, #TJK_DL dt a:active, #TJK_DL dt a:focus {font-weight:bold}
/* the + and - gif in the anchors */
#TJK_DL .DTplus a {background-image:url(toggleDLplus.gif)}
#TJK_DL .DTminus a {background-image:url(toggleDLminus.gif)}
/**********************************/
/**********************************/
#TJK_DL .showDD {position:relative;top:0}
#TJK_DL dd,.hideDD{top:-9999px;position:absolute}
#TJK_ToggleON,#TJK_ToggleOFF {display:inline;cursor:pointer; cursor:hand}

Note: “cursor:hand” is for IE5 Win, but this declaration will make this sheet fail Validation. If Validation is important to you, you can either delete this declaration or move it inside a Conditional Comment.

TJK_ToggleDL_ie5mac.css


/**//*/
#TJK_DL .showDD {display:block}
#TJK_DL dd,.hideDD {top:0; position:relative; display:none}
/**/

For the DOM police

Earlier versions of this script did not use document.write(), I was using the DOM to plug the stylesheets in the HEAD element. Unfortunately, setting the rel attribute of the LINK element makes Safari “go blank” and STYLE fails in IE Win. So, I decided to go with what works!

important noteThis script should work in HTML and XHTML documents.