簡體   English   中英

在單頁pushState Web應用程序中模擬畫外音頁面加載

[英]Simulate Voiceover page load in single-page pushState web application

我正在開發一個單頁面應用程序(SPA),我們正在使用HTML 5 history.pushState模擬多頁面應用程序。 它在視覺上看起來很好,但在iOS Voiceover中表現不正常。 (我認為它不適用於任何屏幕閱讀器,但是我首先嘗試使用畫外音。)

這是我想要實現的行為的一個例子。 這是兩個普通的網頁:

1.html

<!DOCTYPE html><html>
<body>This is page 1. <a href=2.html>Click here for page 2.</a></body>
</html>

2.html

<!DOCTYPE html><html>
<body>This is page 2. <a href=1.html>Click here for page 1.</a></body>
</html>

很好,很簡單。 畫外音如下所示:

網頁已加載。 這是第1頁。
[向右滑動]單擊此處查看第2頁。鏈接。
[雙擊]加載網頁。 這是第2頁。
[向右滑動]單擊此處查看第1頁。已訪問。 鏈接。
[雙擊]加載網頁。 這是第1頁。

這里它再次作為單頁面應用程序,使用歷史記錄操作來模擬實際的頁面加載。

spa1.html

<!DOCTYPE html><html>
<body>This is page 1.
<a href='spa2.html'>Click here for page 2.</a></body>
<script src="switchPage.js"></script>
</html>

spa2.html

<!DOCTYPE html><html>
<body>This is page 2.
<a href='spa1.html'>Click here for page 1.</a></body>
<script src="switchPage.js"></script>
</html>

switchPage.js

console.log("load");
attachHandler();

function attachHandler() {
    document.querySelector('a').onclick = function(event) {
        event.preventDefault();
        history.pushState(null, null, this.href);
        drawPage();
    }
}

function drawPage() {
    var page, otherPage;
    // in real life, we'd do an AJAX call here or something
    if (/spa1.html$/.test(window.location.pathname)) {
        page = 1;
        otherPage = 2;
    } else {
        page = 2;
        otherPage = 1;
    }
    document.body.innerHTML = "This is page " + page +
        ".\n<a href='spa"+otherPage+".html'>Click here for page " +
        otherPage + ".</a>";
    attachHandler();
}

window.onpopstate = function() {
    drawPage();
};

(請注意,此示例不適用於文件系統;您必須從Web服務器加載它。)

這個SPA示例在視覺上看起來與簡單的多頁面示例完全相同,只是第2頁“加載速度更快”(因為它根本沒有真正加載;它在JS中都發生了)。

但在畫外音方面,它並沒有做正確的事情。

網頁已加載。 這是第1頁。
[向右滑動]單擊此處查看第2頁。鏈接。
[雙擊]點擊此處查看第1頁。訪問。 鏈接。
[重點是鏈接! 向左滑動]這是第2頁。
[向右滑動]單擊此處查看第1頁。已訪問。 鏈接。
[雙擊]加載網頁。 這是第1頁。

重點是鏈接,它應位於頁面頂部。

如何告訴Voiceover整個頁面剛剛更新,讀者應該從頁面頂部繼續閱讀?

Jorgen的回答是基於另一個StackOverflow線程讓我走上正軌。

實際修復不是將整個頁面包裝在<div tabindex=-1> ,而是圍繞第一部分(“這是頁面N”)創建<span tabindex=-1>並將其集中。

function drawPage() {
    var page, otherPage;
    // in real life, we'd do an AJAX call here or something
    if (/spa1.html$/.test(window.location.pathname)) {
        page = 1;
        otherPage = 2;
    } else {
        page = 2;
        otherPage = 1;
    }
    document.body.innerHTML = '<span tabindex="-1" id="page' + page + '">This is page ' + page +
        '.</span>\n<a href="spa'+otherPage+'.html">Click here for page ' +
        otherPage + '.</a>';

    document.getElementById('page' + page).focus();
    setTimeout(function() {
        document.getElementById('page' + page).blur();
    }, 0);
    attachHandler();
}

請注意,在此示例中,我們還會在超時時模糊焦點; 否則,非屏幕閱讀器瀏覽器會在跨度周圍繪制一個可見的藍色焦點矩形,這不是我們想要的。 模糊焦點不會影響iOS VO閱讀器的焦點。

根據Dan Fabulich的回答 ,這是一個進一步的改進。

問題是關於使用pushState()更新頁面,所以我將從包含要更新的主要內容區域的語義HTML結構開始。

<body>
    <header role="banner">
        <nav role="navigation">
            <a href="page1.html" onclick="updatePage(1, 'Page 1', this.href); return false;" aria-current="true">Page 1</a> |
            <a href="page2.html" onclick="updatePage(2, 'Page 2', this.href); return false;">Page 2</a>
        </nav>
    </header>
    <main role="main">
        <!-- This heading text is immediately after the nav, so it's a logical place to set focus. -->
        <h1 id="maintitle" tabindex="-1">Page 1</h1>
        <div id="maincontent">
<p>Lorem ipsum</p>
        </div>
    </main>
    <footer role="contentinfo">&copy; 2017</footer>
</body>

JavaScript的:

function updatePage(pageNumber, pageTitle, pagePath) {
    var mainContent;
    if (pageNumber == 1) {
        mainContent = '<p>Lorem ipsum</p>';
    } else if (pageNumber == 2) {
        mainContent = '<p>Dolor sit amet</p>';
    } else {
        return;
    }
    document.getElementById('maincontent').innerHTML = mainContent;

    // TODO: Update the address bar with pushState()

    // TODO: Update the nav links, so only one link has aria-current="true"

    // Keep the browser title bar in sync with the content.
    document.title = pageTitle + ' - My Example Site';

    // Set focus on the visible heading, so screen readers will announce it.
    var mainTitleElement = document.getElementById('maintitle');
    mainTitleElement.innerHTML = pageTitle;
    mainTitleElement.focus(); // TODO: Add a 0ms timer, to ensure the DOM is ready.
}

關於焦點輪廓(也稱為焦點環):

  • 不要blur() 屏幕閱讀器通常可以恢復,但他們無法重新宣布當前的線路,而且它是WCAG禁忌。
  • 比模糊更糟糕的是CSS span {outline:none} ,但這是有風險的。 我只會在tabindex=-1靜態文本上使用它,這並不理想,因為它讓視力不佳的鍵盤用戶迷失方向。
  • 我見過的最好的解決方案是Alice Boxhall的輸入模式prollyfill

我沒有iPhone,但在另一個stackoverflow線程中提供了解決方案。 將內容包裝在tabindex為-1的元素中,並以編程方式將焦點設置在該元素上。

function drawPage() {
    var page, otherPage;
    // in real life, we'd do an AJAX call here or something
    if (/spa1.html$/.test(window.location.pathname)) {
        page = 1;
        otherPage = 2;
    } else {
        page = 2;
        otherPage = 1;
    }
    document.body.innerHTML = '<div tabindex="-1" id="page' + page + '">This is page ' + page +
        '.\n<a href='spa'+otherPage+'.html'>Click here for page ' +
        otherPage + '.</a></div>';

    document.getElementById('page' + page).focus();
    attachHandler();
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM