明日のためにその2
ツールバー・ボタンのWAI-ARIA対応のための要見直しメモ
現状のソース
/* JavaScript */ /* toggleToolbar() ツールバー・ボタンのクリックで表示・非表示を切り替え */ function toggleToolbar(obj) { 'use strict'; var _win = window, _doc = document, tool = [{id : 'navi-button', target : '#global-navigation'}, {id : 'search-button', target : '#utility > #site-search'}, {id : 'info-button', target : '#utility-list'}], cName = obj.getAttribute('class'), spch = _win.matchMedia ? _win.matchMedia('speech').matches : false, target, tObj, i = 0, l = tool.length; if(cName === 'opener') { for(i = 0; i < l; i++) { target = _doc.querySelector(tool[i].target); obj.id === tool[i].id && target ? (tObj = target, target.setAttribute('class', 'show'), obj.setAttribute('class', 'closer')) : (target && /show/.test(target.getAttribute('class')) && target.setAttribute('class', 'hide'), _doc.getElementById(tool[i].id).setAttribute('class', 'opener')); } spch && tObj && _win.confirm('「' + tObj.title + '」に移動しますか?') && (_win.self.location.href = '#' + tObj.id); obj.id === 'search-button' ? _doc.getElementById('search').focus() : tObj && tObj.focus(); } else if(cName === 'closer') { for(i = 0; i < l; i++) { target = _doc.querySelector(tool[i].target); target && /show/.test(target.getAttribute('class')) && target.setAttribute('class', 'hide'); _doc.getElementById(tool[i].id).setAttribute('class', 'opener'); } !spch && obj.blur(); } } (function(_win, _doc) { 'use strict'; /* setToolbar() ツールバーの設定 */ function setToolbar() { if(_doc.defaultView.getComputedStyle(_doc.getElementById('toolbar'), '').display !== 'none') { var navi = _doc.getElementById('navi-button'), srch = _doc.getElementById('search-button'), info = _doc.getElementById('info-button'); _doc.getElementById('home-button').addEventListener('click', function() { _win.self.location.href = 'http://asamuzak.jp/'; }, false); navi.setAttribute('class', 'opener'); navi.addEventListener('click', function() { toggleToolbar(this); }, false); _doc.querySelector('#utility > #site-search') ? (srch.removeAttribute('disabled'), srch.setAttribute('class', 'opener'), srch.addEventListener('click', function() { toggleToolbar(this); }, false)) : srch.setAttribute('disabled', 'disabled'); _doc.getElementById('utility-list') ? (info.removeAttribute('disabled'), info.setAttribute('class', 'opener'), info.addEventListener('click', function() { toggleToolbar(this); }, false)) : info.setAttribute('disabled', 'disabled'); } } _doc.addEventListener('DOMContentLoaded', function() { setToolbar(); }, false); })(window, document);
<!-- HTML --> <div id="toolbar" role="menubar"> <button id="home-button" type="button" title="ホーム" role="menuitem"><img src="http://asamuzak.jp/svg/home.svg" alt="ホーム" /></button> <button id="navi-button" type="button" title="ナビゲーション" role="menuitem" aria-controls="global-navigation"><img src="http://asamuzak.jp/svg/navi.svg" alt="ナビゲーション" /></button> <button id="search-button" type="button" title="検索" role="menuitem" aria-controls="site-search"><img src="http://asamuzak.jp/svg/search_brg.svg" alt="検索" /></button> <button id="info-button" type="button" title="お知らせ" role="menuitem" aria-controls="utility-list"><img src="http://asamuzak.jp/svg/info.svg" alt="お知らせ" /></button> </div>
- classの差し替えで制御するのではなくて、aria-selectedとaria-hiddenで制御
- aria-controlsの設定はsetToolbar()で? さらに、targetはaria-controlsの値を取得するよう変更?
- media="speech"への対応は…サポートしているブラウザがない現状では不要かな?
- そもそものマークアップは妥当? a要素でマークアップしておいてスクリプトでボタンに差し替えるべき? つーか、listだよな…orz
修正後
/* CSS */ .hide { position: absolute; left: -9999px; width: 0; height: 0; overflow: hidden; } .show { (適宜) }
/* JavaScript */ /* * setToolbar(), toggleToolbar() * ツールバー・ボタンのクリックで表示・非表示を切り替え * Copyright (c) 2014 Kazz * http://asamuzak.jp * Dual licensed under MIT or GPL * http://asamuzak.jp/license */ (function(_win, _doc) { 'use strict'; function setToolbar() { var toolbarSetting = function() { // c : コントローラとなるボタン // t : 表示・非表示を切り替えるターゲット return [{ c : 'navi-button', t : 'global-navigation' }, { c : 'search-button', t : '#utility > #site-search' }, { c : 'info-button', t : 'utility-list'}]; }; var setEvent = function(o, a) { o.addEventListener('click', function() { toggleToolbar(this, a); }, false); }; for(var _$ = toolbarSetting(), c, t, i = 0, l = _$.length; i < l; i++) { (c = _doc.getElementById(_$[i].c) || _doc.querySelector(_$[i].c)) && ((t = _doc.getElementById(_$[i].t) || _doc.querySelector(_$[i].t)) ? (c.removeAttribute('disabled'), c.setAttribute('class', 'opener'), c.setAttribute('aria-controls', t.id), setEvent(c, _$), t.setAttribute('aria-labelledby', c.id), t.setAttribute('class', 'hide'), t.setAttribute('tabindex', '-1')) : c.setAttribute('disabled', 'disabled')); } } function toggleToolbar(obj, tool) { var c, t, i = 0, l = tool.length; switch(obj.getAttribute('class')) { case 'opener' : for(i = 0; i < l; i++) { c = _doc.getElementById(tool[i].c) || _doc.querySelector(tool[i].c); t = _doc.getElementById(tool[i].t) || _doc.querySelector(tool[i].t); c === obj && t ? (c.setAttribute('class', 'closer'), t.setAttribute('class', 'show')) : (c && c.setAttribute('class', 'opener'), t && t.setAttribute('class', 'hide')); } break; case 'closer' : for(i = 0; i < l; i++) { (c = _doc.getElementById(tool[i].c) || _doc.querySelector(tool[i].c)) && c.setAttribute('class', 'opener'); (t = _doc.getElementById(tool[i].t) || _doc.querySelector(tool[i].t)) && t.setAttribute('class', 'hide'); } break; } } _doc.addEventListener('DOMContentLoaded', setToolbar, false); })(window, document);
"明日のためにその2"へのTwitter上でのコメントやRT
9件のツイートがあります。
ツイート 1
asamuzaK.jp : 明日のためにその2 / ツールバー・ボタンのWAI-ARIA対応のための要見直しメモ http://t.co/I9wSMrzbiE
ツイート 2
とりあえずFocusTalkの体験版の有効期限が切れる前に対応して検証しなければ PC-Talkerは…試用期限が1ヶ月なんでもう切れたorz http://t.co/I9wSMrzbiE
ツイート 3
ほぼ完成 当初は表示・非表示に合わせてaria-hiddenも操作しようとしたけど、よくよく考えたら「見た目」だけの都合なので、スクリーンリーダーでは常時読み上げさせるべきだと気がついた asamuzaK.jp : 明日のためにその2 http://t.co/I9wSMrzbiE
ツイート 4
具体的には、表示・非表示は、displayの切り替えではなくて、CSSオフスクリーンによるポジショニングで制御 http://t.co/I9wSMrzbiE
ツイート 5
ってことは、スクリーンリーダーではそもそもツールバーが要らないことになるので、こっちにaria-hiddenを設定することにした http://t.co/I9wSMrzbiE
ツイート 6
そのテストケース http://t.co/ouYJCaXZ3Y http://t.co/I9wSMrzbiE
ツイート 7
サイトに反映 / asamuzaK.jp : 明日のためにその2 / ツールバー・ボタンのWAI-ARIA対応のための要見直しメモ http://t.co/I9wSMrzbiE
ツイート 8
修正後のスクリプト例を汎用化してみた / asamuzaK.jp : 明日のためにその2 / ツールバー・ボタンのWAI-ARIA対応のための要見直しメモ http://t.co/I9wSMrzbiE
ツイート 9
スクリプト無効や古いブラウザではツールバーを表示していない(display:none)のでaria-hidden="true"はあらかじめ指定 で、ツールバーを表示する際にはaria-hidden="false"に変更することにした http://t.co/wxXUiItPku