Desenvolvendo AJAX acessível aos leitores de tela

Publicado em: 26/05/2005

Autores: Gez Lemon e Steve Faulkner
URL do original: http://juicystudio.com/article/making-ajax-work-with-screen-readers.php
Título original: Making Ajax Work with Screen Readers
Traduzido com autorização expressa do autor

Sumário

A comunidade envolvida com a acessibilidade está atenta para os itens de acessibilidade envolvendo os scripts rodando no lado do cliente e em particular aos scripts que usam Asynchronous JavaScript and XML (Ajax) para produzir aplicações Rich Internet. Steve Faulkner da Vision Australia e membro fundador do Web Accessibility Tools Consortium (WAT-C) e eu, como representantes do grupo The Paciello Group (TPG) concentramos nossos esforços no sentido de fazer os scripts Ajax e outros scripts rodando no lado do cliente acessíveis às tecnologias assistivas..

O grupo da WAI - Web Accessibility Initiative's - Protocols and Formats working group levantou alguns conceitos de acessibilidade relativos a este assunto e nós, baseados naqueles conceitos estivemos investigando métodos para garantir que aplicações Ajax sejam compatíveis com as principais tecnologias assistivas existentes. A má notícia é que não é possível fazer Ajax funcionar em cada uma das tecnologias assistivas hoje empregadas bem assim como não é possível fazer Ajax funcionar em navegadores antigos, contudo, mas nós explicamos os itens fundamentais; como informar os usuários da tecnologia assistiva que uma mudança ocorreu, e como podem interagir com o aquele conteúdo. Para ilustrar nossas descobertas, nós descrevemos de modo sumário o comportamento dos leitores de tela mais populares.

Autores: Gez Lemon e Steve Faulkner

Índice

Modos de leitura de tela

Para possibilitar o entendimento de como desenvolver Ajax acessível aos leitores de tela é necessário conhecer como funciona um leitor de tela. Para cumprir sua finalidade, um leitor de tela faz uma varredura da página e coloca seu conteúdo em um buffer virtual. Este buffer virtual assim gerado é usado pelo leitor para permitir ao usuário navegar e interagir com a página. Sem o buffer virtual, o leitor poderá acessar somente algumas porções da página, tais como âncoras e elementos da interface, ficando impossibilitado de fornecer ao usuário condições para interagir com outros elementos e seus nós descendentes no conteúdo, tais como imagens, listas, tabelas e outros mais. O buffer virtual dos leitores de tela tem seus nomes especificados de acordo com o fabricante, tal como Virtual Focus mode na Supernova, contudo eles se prestam a mesma finalidade, independente do nome que tenham recebido. A seguir uma descrição de como o buffer virtual foi implementado no leitor de tela JAWS e no Windows-Eyes.

JAWS PC Virtual Modo Cursor

O buffer virtual do JAWS é denominado Jaws PC Virtual Modo Cursor — Virtual PC Cursor mode —. Virtual PC Cursor mode está habilitado por default quando lendo um documento HTML em uma aplicação que lhe ofereça suporte (tal como Internet Explorer e Firefox com JAWS 7.0), e pode ser desabilitado usando o atalho de teclado Insert + Z. Neste modo o usuário estará apto a acessar elementos HTML e seus atributos, tal como o alt dos elementos img.

Quando em modo Virtual PC Cursor mode, o JAWS comporta-se de maneira inconsistente face aos scripts no lado do cliente. O JAWS é capaz de responder satisfatoriamente aos eventos básicos dos scripts, tal como click e keypress, e sempre que tais eventos ocorrem, faz uma nova varredura para atualizar o buffer virtual e refletir qualquer mudança no conteúdo da página. O problema com Ajax é que as mudanças no conteúdo em geral não se fazem imediatamente após a ocorrência do evento; usualmente o conteúdo será adicionado via o evento onreadystatechange do objeto XMLHttpRequest. O interessante é que JAWS 7.0 responde ao evento onreadystatechange quando usado no Firefox, mas não responde no Internet Explorer. A falha na resposta para o evento onreadystatechange juntamente com um inadequado tratamento por parte dos autores, nas partes do documento que mudam são os principais fatores para o não funcionamento ou funcionamento inconsistente de aplicações Ajax . O único maneira de se garantir sucesso no funcionamento do JAWS em modo Virtual PC Mode (o modo default do leitor e que permite ao usuário interagir com o conteúdo da página) é via uso dos eventos click, keypress, ou mouseover, que obviamente não é uma boa solução para Ajax.

A partir da versão 6 do JAWS foi introduzido o comando 'refresh' para o Virtual PC Cursor através do atalho de teclado Insert + Esc. Isto significa que o usuário poderá acessar conteúdo gerado dinemicamente na página por aquele atalho. O problema esta em avisar o usuário que o conteúdo mudou. Uma solução que nós consideramos foi a de adicionar conteúdo avisando ao usuário para fazer o refresh do buffer virtual como resposta para um evento click/keypress e repor o conteudo quando o evento onreadystatechange acontecer no objeto XMLHttpRequest. A suposição para esta solução é a de que usuários do JAWS 6 e posteriores poderiam usar o comando Refresh do Virtual PC Cursor, e usuários das versões mais antigas e de outros leitores de tela que utilizam baffer virtual poderiam habilitar e desabilitar o modo virtual — por exemplo, usando o atalho Insert + Z duas vezes no JAWS em modo Virtual PC Cursor para o refresh necessário.

Ao testar esta técnica no Internet Explorer, o aviso para o refresh do buffer virtual funcionou no JAWS, contudo ao acionar o atalho Insert + Esc apesar de ter sido anunciado, pelo leitor que a página tinha sido atualizada, a leitura do texto atualizado não se iniciou. Ainda no JAWS com Internet Explorer, a ação de desabilitar e habilitar o modo Virtual PC Cursor mode resultou apenas em anúncio, pelo leitor, que o modo havia sido. O JAWS com Firefox responde normalmente ao evento onreadystatechange, assim o conteúdo de aviso ao usuário com uso do evento click é sobrescrito pelo conteúdo do evento onreadystatechange, e anunciado ao usuário. Como o Firefox responde diretamente ao evento onreadystatechange, e o método de desabilitar/habilitar o modo virtual não anuncia o novo conteúdo, não há vantagens em aprofundar estudos sobre esta técnica.

JAWS PC Modo Cursor

O Jaws PC Modo Cursor — Jaws PC Cursor mode — é o oposto do modo Virtual PC Cursor mode no sentido de que ele não usa o buffer virtual. Neste modo, o usuário inteage diretamente com a aplicação e focar em conteúdos que possam ser focados por tecnologias não assistivas, tais como âncoras e elementos de interface. Se Ajax é usado, para que funcione neste modo ficará dependente da capacidade do navegador em tratar scripts e não ficar dependente de alguns poucos eventos capazes de fazer JAWS responder para um refresh do buffer virtual como descrito para o modo Virtual PC Cursor mode. Embora o usuário fique bastante limitado quando no modo PC Cursor mode, ele poderá ativar links e botões de comando. Se o conteúdo gerado pelo evento onreadystatechange for capaz de receber foco, o usuário será notificado e poderá acessar o conteúdo gerado. As especificações para o HTML limitam os elementos que podem receber foco, assim se o conteudo gerado estiver em um elemento que não possa receber foco, um trabalho extra será necessário para que esta solução funcione. Para maiores informações ver a seção adiante informando ao leitor de tela que uma mudança ocorreu no conteúdo.

JAWS Modo Formulário

O modo Jaws Modo Formulário — Jaws Form Mode — é idêntico ao modo PC Cursor mode. JAWS associa os textos para controles de formulário que foram marcados apropriadamente e faz a correspondência exata de um controle com seu elemento label ou procura o texto imediatamente à esqueda ou acima do controle (para checkboxes e radio buttons a procura é para o texto à direita)para fazer a correspondência. Para entrar no modo Forms Mode basta pressionar a tecla Enter quando uma caixa de edição receber o foco.

Como Ajax é usado para construção de aplicações é natural que se utilize formulários em seus elementos de interface. Isto significa que a interação do usuário com controles de formulário funcionam corretamente com Ajax quando o JAWS estiver em modo Forms Mode ou modo PC Cursor mode, porém o usuário terá que habilitar o modo Virtual PC Cursor mode para interagir com conteúdo que não seja formulário.

Windows-Eyes Modo Navegador

Windows-Eye Modo Navegador — Windows-Eye Browser Mode — é o nome dado ao buffer virtual do Windows-Eyes e pode ser habilitado/desabiliatdo vis o atalho de teclado Control + Shift + A. Assim como acontece com o JAWS, também Windows-Eyes quando com buffer virtual habilitado não tem acesso a conteúdo gerado dinamicamente com o evento onreadystatechange do objeto XMLHttpRequest no Internet Explorer. Windows-Eyes responde aos eventos básicos, tais como click e keypress, e assim como o JAWS, atualiza o buffer virtual quando o modo Browse Mode é desabilitado e habilitado novamente.

Quando o modo Browse Mode fro desabilitado, o Windows-Eyes focará apenas em âncoras e elementos de interface e será incapaz de interagir com outros elementos HTML. Para interagir com controles de formulário o Browse Mode deve ser desabilitado. Se Ajax for ativado em resposta a eventos em âncoras ou em elementos de interface, o usuário será informado pelo leitor que o conteúdo mudou tal como acontece com o JAWS. Tanto o JAWS como o Window-Eyes são capazes de ler conteúdos atualizados dinamicamente quando não estiverem em modo Browse/Virtual PC mode, porém o conteúdo atualizado estará disponível como parte do texto disponível na tela.

Informando ao leitor de tela que uma mudança ocorreu no conteúdo

Se o conteúdo foi alterado via script content, isto deverá ser informado ao leitor de tela. Sem a existência de um mecanismo capaz de detectar o que mudou, um usuário de leitor de tela não será informado da mudança, ou ainda, será informado mas terá que ler todo o documento para saber o que mudou. Por exemplo: quando conteúdo é inserido na página via script o Windows-Eyes responde o seguinte:

Loading Page. Load Done. Looking for visible line.
(Carregando a página. Página carregada. Procurando linha de leitura.)

A última linha de leitura é aquela que contém o elemento ativado pelo usuário para produzir novo conteúdo, assim o usuário não terá a mínima idéia de como encontrar o que mudou. Para resolver isto o método focus de ECMAScript poderá ser usado para colocar o foco no local da página que mudou. Para que isto funcione é necessário que o elemento alvo possa receber foco. No HTML (e XHTML) os elementos que podem receber foco são; a, area, button, input, object, select, e textarea.

Em XHTML 2, todos os elementos podem receber foco, mas nas atuais especificações para HTML 4.01 e XHTML 1.x somente elementos âncora e elementos de interface podem receber foco. Para contornar este problema a WAI — The Web Accessibility Initiative's Protocols and Formats working group propos a Dynamic Accessible Web Content Roadmap que sugere usar valor -1 paratabindex em elementos que não podem receber foco e formalizou tal proposta em States and Adaptable Properties Module. A necessidade de se fazer com que todos os elementos possam receber foco foi reconhecida pela Web Applications 1.0.

o atributo tabindex aceita valoresc entre 0 e 32767. Um valor positivo determina a ordem em que um elemento deve ser acessado quando a nevegação for pelo teclado. Um valor 0 significa que o acesso ao elemento deva ser feito na ordem em que ele aparece no código fonte do documento. Atribuir o valor para o atributo tabindex igual a 0 em um elemento que não seja uma âncora ou um elemento de interface significa que ele poderá receber foco via ECMAScript, contudo poderá confundir os usuários navegando com teclado. Atribuir o valor para o atributo tabindex igual a -1 significa que o elemento poderá receber foco via ECMAScript, contudo não será colocado na ordem de tabulação. Tanto o Internet Explorer como o Firefox suportam para tabindex o valor igual a -1, mas isto não funciona para os demais navegadores. Por exemplo; o valor -1 para o atributo tabindex é ignorado pelo Safari e o elemento não recebe o foco via o método focus do ECMAScript.

Quando um elemento que normalmente não pode receber foco, como um parágrafo por exemplo, via um valor negativo para tabindex, o comportamento do leitor de tela varia de acordo com o modo em que ele está — no modo buffer virtual o leitor foca o elemento mas não lê automaticamente o conteúdo, se estiver co m o modo virtual desabilitado, ai sim lê o conteúdo. No modo buffer virtual o usuário tem que solicitar ao leitor (Insert + Down arrow no JAWS e Down arrow no Windows-Eyes e Supernova) que leia o conteúdo após o elemento que recebeu foco. Se o foco for para um elemento âncora, então neste caso a leitura será automática.

Atribuir um valor -1 para o atributo tabindex de um elemento para que ele possa receber foco faz com que o conteúdo seja lido, contudo será interpretado erroneamente como sendo uma caixa de edição pelo Windows-Eyes quando Browse Mode estiver desabilitado, tal como é prescrito por Microsoft Active Accessibility (MSAA). A seguir mostramos um trecho extraido do MSAA para um parágrafo que recebeu o atributo tabindex com um valor igual -1.

Trecho do MSAA
Name "Content for paragraph."
Value none [null]
Role editable text
State focused, focusable

O JAWS simplesmente anuncia para o usuário o texto em foco e não se reporta ao elemento como se fosse uma caixa de edição. Lamentavelmente esta técnica não funciona com o Home Page Reader (HPR), pois embora ele suporte scripts, não oferece suporte para o método focus.

Estruturando conteúdos para aplicações Ajax

Existem várias maneiras de estruturar conteúdos para que uma aplicação Ajax funcione corretamente em um leitor de tela. A mais simples e talvez a melhor é a de se fazer com que as partes da aplicação que exigem ativação pelo usuário, estejam em elementos para formulários. Esta solução permite informar ao usuário sobre mudanças, focando na parte do documento que foi alterada. Isto requer que o usuário desabilite/habilite o mode buffer virtual, mas é isso exatamente que o uauário espera quando interage com formulários.

Se a parte alterada do documento está no formulário, então surge um problema; the changed part of the content is in the form itself, then this presents a problem; although the user can get at the text, they won't be able to interact with the content as they would if they were in virtual buffer mode. Tomemos como exemplo para ilustrar esta situação uma tabela de dados incorporada em um formulário (uma estruturação destas poderia ser melhorada, mas vamos considerar para efeito de exemplo que seja uma solução plausível). Se um dado em uma célula da tabela for atualizado em resposta ao evento onreadystatechange o foco pode ser dado a célula e o leitor anunciará a atualização. O problema é que a tabela contento o texto atualizado não será mais reconhecida como uma tabela e o usuário será incapaz de localizar os headers da tabela e navegar o restante da tabela. Para reverter esta situação o usuário terá que voltar ao modo buffer virtual. Como os leitores de tela sempre anunciam o atributo title, este poderia ser usado para os controles de formulário que possam receber foco (inclusive elementos que não sejam de interface com um específico valor para o atributo tabindex) e que não estejam associados a um label. A seguir um exemplo de como atualizar o conteudo de uma célula de tabela em resposta ao evento onreadystatechange.

var objCurrent = document.getElementById('update');
var objReplacement = document.createElement('td');

// Set the title attribute to prompt the user to change mode
// This should use simpler language than used here, as the user
// isn't likely to understand the concept of a virtual buffer
objReplacement.setAttribute('title', 'Switch to virtual buffer');
// When the element loses focus, remove the attribute for other
// user agents
objReplacement.onblur = function(){this.removeAttribute('title');};

// Set a negative tabindex attribute value so the element 
// can receive focus
objReplacement.tabIndex = -1;

objReplacement.setAttribute('id', 'update');
objReplacement.appendChild(document.createTextNode(strResult));

// Replace the existing node with the new node
objCurrent.parentNode.replaceChild(objReplacement, objCurrent);
// Set focus to the element
objReplacement.focus();

Se a interação com a aplicação não for por formulário, o mais importante é avisar ao usuário para que ele desabilite o modo modo buffer virtual (tal como ele faria para interagir com um formulário). Isto não é tão simples como parece, pois será necessário usar instruções muito claras ao usuário do leitor de tela que na sua maioria desconhece os detalhes técnicos do software que estão utilizando — da mesma forma que usuários de navegadores visuais não necessariamente conhecem como redimensionar os textos no navegador. Uma solução simplista é a de disponibilizar uma página de ajuda, facilmente localizável na aplicação, explicando buffer virtual e contendo uma tabela mostrando os atalhos para habilitá-lo e desabilitá-lo nos leitores de tela mais populares. A tabela a seguir mostra os atalhos de teclado para habilitar e desabilitar o buffer virtual dos leitores de tela que nós usamos para testes.

Mudar Virtual Cursor
Leitor Atalho
JAWS Insert + Z
Windows-Eyes Control + Shift + A
Supernova Left Control + 4

Exemplos de Ajax amigáveis a leitores de tela (em inglês)

Para exemplificar os conceitos apresentados neste artigo, nós desenvolvemos três exemplos de aplicação Ajax. Todos eles funcionam como esperado quando o buffer virtual esta desabilitado com o Internet Explorer. Os exemplos 1 e 2 funcionam com o Firefox e JAWS 7 em modo virtual.

Example 1 — Random Fact Generator (link)
Example 2 — Random Fact Generator (anchor)
Example 3 — Random Fact Generator (form)

Leitura complementar (em inglês)