[英]When supporting frames, How to get an event listener to respond to the whole document?
我正在向使用框架的舊版應用程序添加輔助功能。 我目前正在研究跳過導航功能。
window.top
的 DOMkeydown
偵聽器來捕捉Tab
按下並顯示 SkipNav - 它有效document
,而不是 SkipNav,但它只響應 SkipNav 內的點擊我已經為事件偵聽器嘗試了各種選項組合。 目前的選項是: { capture:true, passive:true }
,據我所知,這個偵聽器將首先被調用,並且事件不能被任何冒泡處理程序取消。
這是我的SkipNavigation
object 的create
方法:
// creates DOM elements, sets up event listeners
create()
{
this.div = document.createElement('div');
this.div.setAttribute('id', 'skip_nav_div');
this.div.setAttribute('role', 'navigation');
this.div.setAttribute('aria-label', 'skip navigation');
this.div.setAttribute('tabindex', '-1');
this.div.className = 'SkipNavigation';
this.button = document.createElement('button');
this.button.setAttribute('id', 'skip_nav_button');
this.button.textContent = 'skip to main content';
this.button.classList = 'btn btn-light';
this.button.addEventListener('click', () => { this.skipNav(this) });
this.div.appendChild(this.button);
document.body.appendChild(this.div);
this.current_element = null;
// This event listener will abort itself after a Tab key is pressed for the
// first time.
// It will display a button to skip to main content if a Tab is pressed.
this.tab_controller = new AbortController();
document.addEventListener('keydown', (e) =>
{
switch (e.key)
{
case 'Tab':
e.preventDefault();
// save currently focused element
this.current_element = document.activeElement;
// check if there's content to skip to
if (this.getContent())
{
// show the SkipNav
this.show(e);
}
// turn off this event listener
this.tab_controller.abort();
break;
default:
// do nothing
}
}, {signal: this.tab_controller.signal});
this.abortOnClick = function (e)
{
// don't intercept clicks on the button itself
if (e.target === this.button)
{
return;
}
this.tab_controller.abort();
// also hide the SkipNav if currently shown
if (this.div.classList.contains('is-open'))
{
this.hide();
// and reset focus to where the user was
if (this.current_element) this.current_element.focus();
}
document.removeEventListener('click', this.abortOnClick.bind(this), { capture:true, passive:true });
}.bind(this);
document.addEventListener('click', this.abortOnClick.bind(this), { capture:true, passive:true });
}
在我們的一個內部框架中,我有一個事件偵聽器實現了一個不同的 object 的類似目的,它被添加到document
中並且正確響應任何點擊(並且它不使用捕獲)。
我不知道為什么這個abortOnClick
處理程序只響應 SkipNav div。
任何幫助是極大的贊賞。
對腳本的依賴越少越好。
如果我理解正確的話,您目前正在嘗試將 state 添加到跳過導航中,使其只能使用一次。 這給界面增加了額外的復雜性並且是出乎意料的。
目前尚不清楚當前的解決方案實際上是如何通過this.hide
隱藏導航的,重要的是它不會像display: none
那樣從輔助技術中隱藏起來。
我的建議是堅持通過 CSS 在視覺上隱藏跳過按鈕的最佳做法,並依靠自然的 Tab 鍵順序。
以下代碼無效 HTML 並且不適用於 HTML 5 文檔類型。 在框架集文檔類型中,不允許使用框架集和框架以外的元素。
const div = document.createElement('div'); div.setAttribute('id', 'skip_nav_div'); div.setAttribute('role', 'navigation'); div.setAttribute('aria-label', 'skip navigation'); div.className = 'SkipNavigation'; const button = document.createElement('button'); button.setAttribute('id', 'skip_nav_button'); button.textContent = 'skip to main content'; button.classList = 'btn btn-light visually-hidden'; button.addEventListener('click', () => document.querySelector('#main').focus()); div.appendChild(button); document.body.insertBefore(div, document.body.firstChild);
frame { border: 1px dashed grey; }.SkipNavigation { position: absolute; } /* https://www.scottohara.me/blog/2017/04/14/inclusively-hidden.html#hiding-content-visually */.visually-hidden:not(:focus):not(:active) { clip: rect(0 0 0 0); clip-path: inset(50%); height: 1px; overflow: hidden; position: absolute; white-space: nowrap; width: 1px; }
<.DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4:01 Frameset//EN" "http.//www.w3.org/TR/html4/frameset,dtd"> <html> <:-- <frameset rows="100."> <frame title="Nav" src="https://example.com/" /> <frame title="Main content" id="main" src="https://example.com/" /> </frameset> --> <div id="main" tabindex="-1">Main for demonstration</div> <p><a href="#">Some link to demonstrate focus order</a></p> </html>
據我所知,屏幕閱讀器已經內置了框架導航,因此我們應該通過提供有用的名稱來支持它。
此示例使用屬性選擇器通過其 src 屬性查找框架,以防它們不提供名稱或 ID。
document.querySelector('frame[src*="navigation"]').title = "Navigation";
document.querySelector('frame[src*="index"]').title ="Main content";
…
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.