2016-07-07 12 views
7

Mein Interaktionsprozess Benutzer ist wie folgt:Wie erstellt man Screenreader Accessible AJAX Regionen und DOM Updates einfügen/entfernen?

  1. Der Benutzer mit einer Dropdown-Liste angezeigt wird, eine Liste der Städte
  2. Nach einer Stadt Auswahl, ein AJAX-Request erhält alle Gebäude in der Stadt enthält, und fügt sie in ein div ein (diese AJAX-Anforderung gibt eine Liste von Kontrollkästchen zurück)
  3. Der Benutzer kann dann ein Kontrollkästchen aktivieren/deaktivieren, um die Stadt zu einer Tabelle hinzuzufügen, die sich auf derselben Seite befindet. (Diese dynamisch fügt/entfernt Zeilen Tabelle)

Hier ist mein dropdown:

<label for="city-selector">Choose your favorite city?</label> 
    <select name="select" size="1" id="city-selector" aria-controls="city-info"> 
    <option value="1">Amsterdam</option> 
    <option value="2">Buenos Aires</option> 
    <option value="3">Delhi</option> 
    <option value="4">Hong Kong</option> 
    <option value="5">London</option> 
    <option value="6">Los Angeles</option> 
    <option value="7">Moscow</option> 
    <option value="8">Mumbai</option> 
    <option value="9">New York</option> 
    <option value="10">Sao Paulo</option> 
    <option value="11">Tokyo</option> 
</select> 

Hier ist die Ajax-div, das Leergut/bevölkert wird:

<div role="region" id="city-info" aria-live="polite"> 
<!-- AJAX CONTENT LOADED HERE --> 
</div> 

Hier Die Checkbox-Liste, die in das Ajax-Div gesetzt wird:

<fieldset id="building-selector" aria-controls="building-table"> 
    <legend>Select your favorite building:</legend> 
    <input id="fox-plaza" type="checkbox" name="buildings" value="fox-plaza"> 
    <label for="fox-plaza">Fox Plaza</label><br> 
    <input id="chrysler-building" type="checkbox" name="buildings" value="chrysler-building"> 
    <label for="chrysler-building">Chrysler Building</label><br> 
    <input id="empire-state-building" type="checkbox" name="buildings" value="empire-state-building"> 
    <label for="empire-state-building">Empire State Building</label><br> 
</fieldset> 

Und schließlich die Tabelle, die die Städte hält, dass er Benutzer fügt/entfernt

<table id="building-table" aria-live="polite"> 
    <caption>List of buildings you have selected</caption> 

    <tr> 
    <th scope="col">Building name</th> 
    <th scope="col">Delete Building</th> 
    </tr> 

    <tr> 
    <td>Empire State Building</td> 
    <td><button>Delete</button> /td> 
    </tr> 

</table> 

Ich dachte, ich auf dem richtigen Weg war aria-Kontrollen durch die Verwendung = „“ und Arie-live = „“, aber das scheint nicht genug zu sein, damit der Bildschirmleser die Änderungen erkennen kann. Tatsächlich weiß ich nicht, ob etwas in meinem Markup fehlt oder ob ich Alert-Ereignisse oder ähnliches auslösen muss, damit dies funktioniert.

+0

Haben Sie ein funktionierendes Beispiel für eine URL, die wir überprüfen können? Meine erste Reaktion ist, dass ich zwei 'Aria-Live'-Regionen sehe und diese Dinge abwerfen kann, aber ohne eine Seite im vollen Kontext ist dies nicht einfach zu debuggen. – aardrian

+0

Sind zwei lebende Bereiche ein Anti-Pattern? Ich werde daran arbeiten, ein Live-Beispiel hinzuzufügen. Ich muss einige gefälschte Ajax-Anrufe erstellen. – Amir

+0

Es kann problematisch sein, muss aber im Kontext sehen: "Wenn mehr als ein Bereich einer Seite aktualisiert wird, können Bildschirmleser den Typ der Aktualisierung, die auftritt, nicht feststellen, welche Priorität ein Bereich bei der Ankündigung gegenüber einem anderen hat Warnungen an den Benutzer, und ob der gesamte Bereich oder nur ein Teil davon angekündigt werden sollte. "[Quelle] (https://www.webaccessibility.com/best_practices.php?technology_platform_id=121) – aardrian

Antwort

1

Bitte beachten Sie wählen vue.js (Licht-Framework) oder angular2 zu verwenden (schwerer Rahmen), um diese Aufgabe zu machen. Es wird diese Art von dom-js Interaktion sehr vereinfachen, die Sie brauchen. Benutzt es mit aria-live = "höflich" aria-atomic = 'wahr' und es funktioniert. Hier ist die Lösung für Ihren Fall in vue.js:

https://jsfiddle.net/nuLjb4uc/8/

HTML:

Im Kopfteil

<script type="text/javascript" src="https://vuejs.org/js/vue.min.js"></script> 

Und in

<script type="x-template" id="my-template"> 

<label for="city-selector">Choose your favorite city?</label> 
    <select name="select" size="1" id="city-selector" aria-controls="city-info" @change="onCityChange($event)"> 
    <option disabled selected value>-- choose city --</option> 
    <option v-for=" (index, city) of cities" value="{{index+1}}">{{ city }}</option> 
</select> 

<fieldset v-if="currentCityBuildings" id="building-selector" aria-controls="building-table"> 
    <legend>Select your favorite building:</legend> 

    <div v-for="building of currentCityBuildings" aria-live="polite" aria-atomic='true'> 
    <input v-model="building.checked" id="{{ building.name }}" @click='selectBuilding(building)' value="{{ building.name }}" type="checkbox" name="buildings"> 
    <label for="{{ building.name }}">{{ building.name }}</label><br> 
    </div> 
</fieldset> 

<table v-if='checkedCityBuildings' id="building-table" aria-live="polite"> 
    <caption>List of buildings you have selected</caption> 

    <tr> 
    <th scope="col">Building name</th> 
    <th scope="col">Delete Building</th> 
    </tr> 

    <tr v-for="building of checkedCityBuildings" aria-live="polite" aria-atomic='true'> 
    <td>{{ building.name }}</td> 
    <td><button @click='deleteBuilding(building)'>Delete</button></td> 
    </tr> 

</table> 

</script> 

<div id="app"></div> 

JS Körper setzen:

new Vue({ 
    el: '#app', 
    data: { 
    cities: ['Amsterdam','Buenos Aires', 'Delhi', 'Hong Kong', 'London', 'Los Angeles', 'Moscow', 'Mumbai', 'New York', 'Sao Paulo', 'Tokyo' ], 
    currentCityBuildings: null, 
    checkedCityBuildings: null, 
    }, 
    template: '#my-template', 
    methods: { 
    onCityChange: function(e) { 
     var index = e.target.value-1; 
     // instead of below line, you should call proper AJAX function which, when it get data, put them into this.checkedCityBuildings like 'simulateAJAX function do. 
     setTimeout(this.simulateAJAX(this.cities[index]), 1000); 
    }, 

    simulateAJAX: function(city) { 
     this.checkedCityBuildings = null; 
     this.currentCityBuildings = []; 
     this.currentCityBuildings.push({name:'fox-plaza-'+city, checked:false}); 
     this.currentCityBuildings.push({name:'chrysler-building-'+city, checked:false}); 
     this.currentCityBuildings.push({name:'empire-state-building-'+city, checked:false}); 
    }, 

    selectBuilding: function(building) { 
     building.checked = !building.checked; 
     this.checkedCityBuildings = []; 
     for(var b of this.currentCityBuildings) { 
     if(b.checked) this.checkedCityBuildings.push(b); 
     } 
    }, 

    deleteBuilding: function(building) { 
     this.selectBuilding(building) 
    }, 


    }, 

}) 

Ich habe es auf Chrome + ChromeVox-Plugin getestet.

1

Sie beschreiben eine Situation, kein Problem.

Solange Ihr Bildschirmleser den Inhalt lesen kann, wenn sich der visuelle Fokus darauf bewegt (mit Ihren AT-Verknüpfungen), ist es das erwartete Ergebnis.

Der Bildschirmleser wird nicht automatisch in die Checkbox-Liste verschoben, nachdem Sie eine Stadt ausgewählt haben. Das liegt daran, dass der visuelle Fokus des Screenreaders nicht mit dem Standardfokus korreliert ist.

aria-live ist etwas, um eine Ankündigung zu machen, aber wird nicht zulassen, dass Sie mit einem inneren Steuerelement innerhalb des gleichen div interagieren und es würde nicht den visuellen Fokus auf dieses Element verschieben.

In Ihrem Fall, dass Sie die Aktion des Formulars beschreiben sollte:

Wählen Sie eine Stadt in der Liste Ihrer Lieblings Gebäude