This document is a draft, and is designed to show changes from a previous version. It is presently showing added text,changed text,deleted text,[start]/[end] markers,and Issue Numbers.
Changes are displayed as follows:
Adobe Flash Professional version MX and higher
Adobe Flex
This technique relates to:
See User Agent Support for Flash for general information on user agent support.
The problem targeted by this technique only occurs in browsers other than Internet Explorer. Currently however, this technique only works in Firefox. In Firefox, the focus always enters the Flash content at the start of the tab order, even when entering the Flash object by shift-tabbing backward through the tab order. Additionally, JavaScript needs to be enabled for this technique to work.
The objective of this technique is to prevent keyboard traps caused by Flash content embedded in a web page. In browsers other than Internet Explorer, there is a problem related to keyboard accessibility of embedded Flash content. The problem is that, while both the Flash content and the HTML content around it may be keyboard accessible, it is not possible to move keyboard focus between the Flash content and HTML content without using a mouse. Once focus is placed inside the Flash movie, a keyboard user will be trapped there. Similarly, when focus is placed somewhere else on the HTML content (outside the Flash movie), it will be impossible to move focus into the movie.
This issue has been around for a long time, and is related to the way browsers implement embedded plug-ins. Until this problem is fixed, it is up to the Flash developer to come up with a work around. This technique is one of those workarounds. The approach behind this technique is the following:
Two 'neighbor' focusable HTML objects are identified for each Flash movie in the document (one before and one after the movie). These elements can be any HTML elements that are part of the web page's tab order (such as links and form controls).
The Flash movie object itself is added to the document tab order as well, making it possible to tab into the movie.
Inside the Flash movie, the Flash Player maintains its own tab order. Normally, when the start or end of the Flash tab order is reached (when tabbing through the movie), focus will wrap to the beginning or end of the movie's tab order, and it will not be possible to (shift) tab out of it. With this technique however, when a 'focus wrap' is detected focus will instead be moved to the neighboring element in the HTML tab order (allowing a keyboard user to 'break out' of the Flash tab order).
When the SWFFocus class is imported into a Flash project, the following will happen:
A JavaScript <script> tag will be generated and added to the HTML document containing the Flash movie. This JavaScript code will:
Set a tabindex value of "0" on the <object> element of each Flash movie found in the page. This causes the Flash objects to become part of the tab order.
Optionally, create a hidden anchor element before and after the Flash movie, which is used by the SWFFocus class to move focus out of the Flash movie back into the HTML page. Alternatively, the developer can specify existing focusable HTML elements as adjacent tab stops for the Flash movie.
Set event handlers for the Flash movie object, so that when it receives focus, the SWFFocus class is notified to manage the movie's internal tab order.
The SWFFocus class monitors changes in focus within the Flash movie. When a focus wrap is detected in the movie, a JavaScript function will be called to instead move focus back to the neighboring HTML content.
As indicated above, there are two ways in which this technique can be used:
Letting the SWFFocus class generate neighboring focusable elements in the HTML tab order for each Flash movie (demonstrated in example 1 below)
By default, the SWFFocus class will create a hidden link element before and after an embedded Flash movie. These elements are needed as 'anchor' to move focus to when (shift) tabbing out of the Flash movie. This approach is the easiest to implement, as it does not require any additional work by the developer. The downside is that the hidden links will clutter the HTML tab order with meaningless elements (although these elements are only used as tab stops when tabbing _out of_ the Flash movie, not when tabbing _into_ it). Because of this, it is recommended to use the following approach instead:
Explicitly identifying focusable HTML elements that come before and after the a Flash movie in the HTML tab order (demonstrated in example 2 below)
With this approach, the developer can use ID values to identify the elements that come before and after the Flash movie in the HTML tab order. This is done by setting special class names on the Flash movie's <object> element. This is the preferred approach, as it does not cause an unnecessary cluttering of the tab order. However, it does require more work and awareness by the developer (who has to manually set ID values). Also, in some scenarios there simply may not be a next or previous focusable element for a Flash movie.
The two examples below are shown in the working example of Preventing a keyboard trap in Flash content. The example html file has two Flash movies embedded in it. The first Flash movie is embedded with the approach described in example 1. The second example is embedded with the approach described in example 2. The source of Preventing a keyboard trap in Flash content is available. The source zip file contains the SWFFocus class.
Note: To run the example from a local drive (as opposed to running it from a web server), the local directory needs to be added to Flash Player's security settings.
In this example, the SWFFocus class is used without explicitly identifying focusable HTML elements. This will cause SWFFocus to dynamically insert hidden links before and after the Flash movie.
The Flash object in this example is added using SWFObject's dynamic publishing method, which means that the object tag is created dynamically by JavaScript in a way that the browser supports. While this is the recommended approach, it is not a requirement for using this technique. The SWFFocus class will also work when the object tag is hardcoded into the HTML document.
The sample code below shows how to load the movie dynamically with SWFObject.
Example Code:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Keyboard Trap Fix Example</title>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type"/>
<script src="swfobject_2_1.js" type="text/javascript"/>
<script type="text/javascript">
var flashvars = {};
var params = {};
params.scale = "noscale";
var attributes = {};
attributes.id = "FlashSample1SWF";
attributes.name = "FlashSample1SWF";
swfobject.embedSWF("keyboard_trap_fix_custom_as3.swf", "flashSample1", \
"150", "200", "9.0.0", "expressInstall.swf", flashvars, params, attributes);
</script>
</head>
<body>
<p>The following Flash movie automatically generates invisible
links before and after the flash movie, allowing keyboard focus
to move out of the Flash content.</p>
<div id="flashSample1">
<a href="http://www.adobe.com/go/getflashplayer">
<img alt="Get Adobe Flash player"
src="http://www.adobe.com/images/shared/download_buttons/get_flash_player.gif"
/>
</a>
</div>
</body>
</html>
The SWFFocus class needs to be added to a Flash project's source path. The easiest way to achieve this is to copy the com/swffocus/SWFFocus.as file (including the nested directory structure) to the project's root directory.
When the SWFFocus class is added to the movie's source path, it needs to be initialized with the following code:
Example Code:
import com.swffocus.SWFFocus;
SWFFocus.init(this);
The code for the class itself can be found in the source files.
For a large part, this technique is the same as example 1 :
The dynamic loading approach by SWFObject is used to load the Flash movie
The SWFFocus class needs to be added to the movie's sourcepath and initialized in the Flash movie
For more details about these steps, see example 1.
In this case however, special class names are added to the Flash movie object. These class names indicate the ID values of the elements previous and next of the movie in the HTML tab order. The class names are:
'swfPref-<previous ID>', where '<previous element>' should be the ID value of the previous element in the tab order.
'swfNext-<next ID>', where '<next element>' should be the ID value of the next element in the tab order.h
For example, the HTML code could look like this (notice the added class names on the object tag):
Example Code:
<a href="http://www.lipsum.com/" id="focus1">test 1</a>
<object class="swfPrev-focus1 swfNext-focus2"
data="keyboard_trap_fix_as3.swf" tabindex="0"
type="application/x-shockwave-flash"/>
<a href="http://www.lipsum.com/" id="focus2">test 2</a>
Since this example uses SWFObject's dynamic loading, the class names will have to be specified as attribute when SWFObject is initialized. This is demonstrated in the code example below.
Example Code:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Keyboard Trap Fix Example </title>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type"/>
<script src="swfobject_2_1.js" type="text/javascript"/>
<script type="text/javascript">
var flashvars = {};
var params = {};
params.scale = "noscale";
var attributes = {};
attributes.id = "FlashSample2SWF";
attributes.name = "FlashSample2SWF";
attributes["class"] = "swfPrev-focus1 swfNext-focus2";
swfobject.embedSWF("keyboard_trap_fix_as3.swf", "flashSample1", "150",
"200", "9.0.0", "expressInstall.swf", flashvars, params, attributes);
</script>
</head>
<body>
<a href="http://www.lipsum.com/" id="focus1">lorem</a>
<p>The following Flash movie uses existing links in the document
to move focus to when (shift) tabbing out of the Flash content.
The existing links are defined by placing special classnames on
the Flash object.</p>
<div id="flashSample2">
<a href="http://www.adobe.com/go/getflashplayer">
<img alt="Get Adobe Flash player"
src="http://www.adobe.com/images/shared/download_buttons/get_flash_player.gif"
/>
</a>
</div>
<a href="http://www.lipsum.com/">lorem</a>
</body>
</html>
Note: this example assumes that the focusable HTML elements exist and have an ID value at the time SWFObject is called to insert the Flash movie. However, in some situations it is also possible that these elements do not yet exist when the Flash movie is created, or that the elements will be deleted dynamically at a later point. If this happens, it is possible to reassign ID values for previous and next focusable elements. To do this, call the SWFsetFocusIds() method on the Flash movie object, like so:
Example Code:
var o = document.getElementById("FlashSample1SWF");
o.SWFsetFocusIds('prevId', 'nextId');
From that point on the updated IDs will be used to move focus to when tabbing out of the Flash movie.
Resources are for information purposes only, no endorsement implied.
For a Flash movie on a web page:
If possible, confirm that the source of the Flash movie imports and initializes the SWFFocus class
Press the tab key to move through tabbable items on the page
Confirm that it is possible to tab into the Flash content
Continue tabbing and confirm that it is possible to tab out of the flash content
Checks 3 and 4 are true
The main component used in this technique is an external ActionScript class called "SWFFocus". This class was created by Michael Jordan (inspired by the previous work of John Norgaard of Sonokids,), and later modified by Hans Hillen from The Paciello Group.
</tech-info>