第一次參與開源專案——Miniflux——改進A11y(Accessibility)

發佈日期:
編輯日期:

Miniflux是一個開源的feed reader,我也使用它一陣子了。 它本身沒有什麼問題,但當我打開螢幕閱讀器使用時,會有一些不太方便的地方。 雖然寫網頁一陣子了,但都還沒有參與過開源專案,所以我想說就趁這個機會來試試看。 這篇文章會說明我在Miniflux上發現的一些A11y問題以及如何改進。

跳至主要內容

大部分的網頁都存在著一定比例的重複內容,以一個新聞網站新聞文章為例,一開始會有一個橫幅,有該網頁的Logo、全域的導覽列等。真正的內容則是新聞內容。 這樣的排版型式很常見,對一般使用者來說也不構成問題。 但如果網站沒有做出任何調整,會對鍵盤及螢幕閱讀器使用者不太方便。

鍵盤使用者要點選網頁內容的方法只有不斷地按下Tab鍵,前面有幾個按鈕或連結等可互動元件,就得按幾下。 如果該篇新聞內容有一個鍵盤使用者想開啟的連結,而該新聞網站的導覽列有五十個連結(例如該網路放上了所有的hashtag連結),那麼鍵盤使用者就得把這五十個連結都路過一遍,才能到達他的目的地。

但今天這還只是一篇新聞,試想一下,你有十篇該網站的新聞要讀,那麼每一個新聞頁面都得重新經過五十個連結才能到達你要的地方,這樣的使用者體驗非常的糟糕。 螢幕閱讀器使用者也有可能跟鍵盤使用者有一樣的體驗,因為他們在元件中移動的方式比較相似。 跟鍵盤使用者較不一樣的是,螢幕閱讀器可以指定選取目標的類型。例如現在只在標題、連結、按鈕等不同類型的元件中移動。

相較鍵盤使用者,只能使用Tab在可互動的元件中移動,螢幕閱讀器使用者還是有機會避開最糟情況,也就是要跳過五十個不相關的元件才能到達目的地。 一個最快速的解決方法便是在網頁最開頭加上「跳至主要內容」的連結。 這個方法可以地達到WCAG (Web Content Accessibility Guidelines)對於Bypass blocks的要求。 而實際的做法本文就不做講解,推薦閱讀這篇文章《A Deep Dive on Skipping to Content》

而Miniflux雖然有提供一些鍵盤快捷鍵,在一些頁面能直接跳至主要內容,但並非所有頁面都能如此操作,對新使用者來說,也不一定知道有這些快捷鍵。 再來是跳至主要內容這個作法算是一個比較常見,也被列在WCAG的Techniques中,可以預想會有一部份的使用者會嘗試尋找網站是否有提供跳至主要內容的連結,就能讓使用者的操作更為方便。 若往後使用者有熟記了Miniflux的快捷鍵,想改用快捷鍵也不會有什麼影響。

地標

在網頁中使用地標是一個方法,讓使用者能快速理解當前的網頁內容的架構。

  • Banner橫幅(有條件地對應HTML的header)
  • Complementary互補內容(對應HTML的aside)
  • Contentinfo內容資訊(有條件地對應HTML的footer)
  • Form表單(對應HTML的form)
  • Main主要內容(對應HTML的main)
  • Navigation導覽(對應HTML的nav)
  • Region區域(有條件地對應HTML的section)
  • Search搜尋(對應HTML的search)

關於上述有條件地對應,可以閱讀W3C對於地標的說明。 而地標之所以重要,這跟螢幕閱讀器使用者瀏覽網頁的方式有關。螢幕閱讀器可以指定選取目標的類型,而地標也是其中一種類型。

使用地標進行瀏覽也是一部份螢幕閱讀器使用者偏好的方式。螢幕閱讀器使用者可以快速地瀏覽地標來大致了解網頁,例如網頁最頂端是橫幅、主要內容在中間、最後是頁尾。 而這些地標的特性,能讓使用者能預期裡面的內容。例如,橫幅裡通常會有導覽列跟搜尋欄、一些資訊連結會放在頁尾等。 這些資訊能讓螢幕閱讀器使用者不用一個一個去找他們想要的資訊在哪裡。

導覽地標

Miniflux在橫幅中的導覽列有使用了HTML的nav,是全域的導覽連結。但在個別頁面也有另一個連結群組,是屬於個別頁面的連結。 HTML並沒有規定只能存在一個nav,但如果存在多個nav,建議是使用幫nav放上不同的標籤,這樣螢幕閱讀器使用者才能知道,不同的導覽列的用途是什麼。

搜尋地標

Miniflux中搜尋欄並沒有使用HTML search也沒有加上search role於HTML標籤上,因此螢幕閱讀器使用者在使用地標進行導覽時,螢幕閱讀器並不會報出網頁內有搜尋地標。

這個問題不算太難解決,換上HTML search或加上role就行了。 但Miniflux有一個問題是在手機版的頁面預設會將搜尋欄隱藏,點擊Logo按鈕打開選單後才會出現。 這樣會造成的問題是,當一個元件的CSS display屬性的none的時候,螢幕閱讀器便不會把它報讀出來,只有當選單是打開的情況,螢幕閱讀器使用者使用地標進行瀏覽時,螢幕閱讀器才會告訴使用者,這個頁面有搜尋地標。

選單預設是關閉的狀態,便增加了螢幕閱讀器使用者找到搜尋地標的複雜性。 因此這邊我採取的作法是,將搜尋地標從選單中移出,不要讓它預設是隱藏的狀態,如此便能比較容易地使用。

可展開選單

剛剛講到搜尋地標被隱藏在一個需要點擊按鈕後才打開的選單內,這個選單即是可展開選單。可展開選單是很常見的一個網頁元件,可以自已用JavaScript實作,也可以直接使用原生的HTML details與summary。

不管是要自己實作,還是要用HTML,都要注意到幾件事。 第一,當使用者聚焦在按鈕上,使用者要能知道這是一個能觸發展開、關閉選單的按鈕; 第二,如果是可觸發的按鈕,使用者要能知道目前選單的狀態,也就是它當前是展開還是關閉。 這件事情在視覺判斷上不太會有問題,但若今天是一位螢幕閱讀器使用者,便會需要螢幕閱讀器來報讀出當前狀態。

如何讓螢幕閱讀器報讀的實作的方法,可以參考ARIA Authoring Practices Guide的Disclosure (Show/Hide) Pattern範例 一般來說使用HTML details與summary就能提供良好的螢幕閱讀器使用體驗,但也不是完全沒問題。

iOS及macOS的bug

HTML details與summary在蘋果的作業系統——iOS與macOS——使用螢幕閱讀器會遇到兩個問題。 首先是summary並不會被視為是一個按鈕,當螢幕閱讀器使用者切換至以按鈕進行瀏覽時,這個可展開選單的按鈕會被忽略。 再來是選單是開啟還是關閉狀態也不會被報讀出來。 而這個問題在2013年就被回報了,但過了十年這個問題依然存在。 相關解決辦法可以參考這篇文章《The details and summary elements》,或是看蘋果哪天心情好想修這個問題。

表單

表單算是在處理a11y時偏麻煩的一個元件,因為在不同的螢幕閱讀器下,對待它的方式差異也很大。 例如,表單在定義上是地標,但不是所有的螢幕閱讀器都將它視為地標。 再來是輸入欄位,有些螢幕閱讀器會報讀出placeholder,有些不會。

如果有些網站的設計是用placeholder取代欄位標籤(HTML label)那很可能螢幕閱讀器會一陣沉默,使用者會完全沒有頭緒這個欄位要做什麼。 比較穩定的做法,一定還是有明確的欄位標籤,placeholder作參考,例如:欄位標籤為姓名,placeholder為王小胖。 這樣就算placeholder被忽略,使用者依然能知道這毎欄位要輸入什麼。

但如果有標籤就是不能出現在畫面上的情況,這個時候我們可以使用aria-label來幫輸入欄加上說明,就能讓畫面沒有標籤但螢幕閱讀器能報讀出欄位標籤。 實作的方法可以參考這篇文章《Using aria-label to provide an invisible label where a visible label cannot be used》,這也是我在Miniflux上採取的作法。

但表單的問題還是滿多的,我建議一定要用螢幕閱讀器測試過一遍。

文章

文章(HTML article)也算是一個比較特別的元件,它在定義上不算地標,但在Android的螢幕閱讀器TalkBack會將它視為地標,而iOS的螢幕閱讀器則能選擇搜尋頁面中的文章。 所以說文章算是一個有比較多手段能被螢幕閱讀器使用者利用的一個元件。 而要如何改進螢幕閱讀器使用者在瀏覽文章的體驗,可以透過幫它設置標籤跟說明來做到。

舉例來說,一個部落格的文章列表頁面,列出了十篇文章。 每篇文章的內容包含了標題、簡短的內容摘要、發佈時間、作者。 我們是怎麼判斷我們想不想讀一篇文章。 我們可能先看標題,有興趣的話看一下摘要,協助判斷內容是不是真的是我想讀的。可能再看一下作者是誰,發表的日期是不是最近的,也許這個文章是有時效性的。 如果確認是我們有興趣的內容,我們就會點擊文章的連結。 不同的螢幕閱讀器在聚焦到文章上會有不同的行為,例如iOS的VoiceOver會唸出文章中的第一個元件;Android的TalkBack會概略的說明裡面有什麼元件,有一個清單、連結等。

有時候這些行為剛好會得到良好的使用者體驗,例如文章中的第一個元件湊巧是文章標題,那麼iOS的VoiceOver就會把標題唸出來。 而這剛好也是我們在判斷是否要讀一篇文章時,很重要的一個依據。 但並不是每次HTML都能湊巧是這個結構,這個時候,我們就能透過設定文章的標籤(aria-label)及說明(aria-describedby),來讓不同螢幕閱讀器有較一致的行為。 詳細的做法可以參考《Using aria-label to provide labels for objects》《Using the aria-describedby property to provide a descriptive label for user interface controls》

我們可以將文章標籤設定為文章標題,說明設定為文章的摘要、作者等,依照網站內容去決定哪些資訊能幫助使用者判斷該文章是否是使用者有興趣的。 如果說整個部落格永遠都只會有一個作者發文,那麼把文章作者列入文章說明就會比較多餘了。

螢幕閱讀器輔助說明

有的時候,一些文字訊息會因為擺放的位置,可以提供判斷該文字所要傳達的意思。 例如:一個數字五,擺放在餅乾的旁邊,我們可以合理的判斷,也許它是在說明現在有五片餅乾。 但我們如果再往上看,會看到一個標題,上面寫著「目前庫存」,那麼就更能證實我們剛剛的猜測是正確的。

這些都是建立在我們有視覺進行輔助判斷的前提下,但假設今天是螢幕閱讀器使用者,他今天只聽到螢幕閱讀器說了一個「五」,對使用者來說,應該是會相當的困惑,這個五是什麼意思。 當然螢幕閱讀器使用者可以會往前或往後移動,去理解上下文,幸運的話,他能找到能輔助他判斷這個數字的意思的資訊。 但如果今天一個網站因為視覺呈現的考量,在網頁上不希望顯示這些資訊的話可以怎麼做。 這個時候我們可以透過CSS讓輔助資訊在畫面中消失,但不去隱藏它,詳細說明可以參考這篇文章《CSS in Action: Invisible Content Just for Screen Reader Users》

假設今天畫面只允許出現「餅乾:五」這幾個字,也許在顯示器的上方有貼了一張紙,寫著「目前庫存」,所以設計師不允許在網頁中再顯示其它字了。 目前螢幕閱讀器會報讀為:「餅乾(停頓)五。」 可以嘗試的做法便是將文字改為
餅乾:<span class="sr-only">目前庫存為</span>五
也就是將輔助資訊從畫中隱藏。
現在螢幕閱讀器會報讀為:「餅乾(停頓)目前庫存為五」,但畫只會顯示「餅乾:五。」

連結與按鈕這兩個元件時常被混用,但它們有著不同的目的。

An interactive reference to an internal or external resource that, when activated, causes the user agent to navigate to that resource. ——引述自Accessible Rich Internet Applications (WAI-ARIA) 1.3

連結觸發時,只應該發生移動這件事,例如本文一開始提到的跳至主要內容。此外,還有頁面切換,移動到另外一個網址去。

An input that allows for user-triggered actions when clicked or pressed. Buttons are mostly used for discrete actions. ——引述自Accessible Rich Internet Applications (WAI-ARIA) 1.3

按鈕觸發時,通常會預期有動作將會執行,例如本文提到的可展開選單開啟。 但按鈕的觸發也可能會發生移動,例如送出表單的按鈕,發表文章後網頁被重新導向新文章頁面。 由此可知,以頁面是否移動、改變並不能做為區分連結與按鈕的方式。比較根本上的區分還是是否有動作被執行了,例如選單打開、新文章建立、刪除等。

而為什麼這個區分很重要?因為對於螢幕閱讀器來說,這兩者是完全不同的兩個類別,螢幕閱讀器使用者會依照當前使用需求來決定瀏覽模式。 例如使用者目前明確知道這個頁面有一個表單,這個時候他就可以將可瀏覽元件限制在按鈕。如此一來,使用者便能跳過很多不必要的元件,找到他要的目標。 除此之外,若以鍵盤操作,按鈕在大多數瀏覽器中,預設可以用SpaceEnter鍵觸發。而連結則預設只能使用Enter鍵。

結語

以上是這次我在改進Miniflux的a11y時所做的改動,這些改動也於2.1.0版本中發佈了。

這也是我第一次參與開源軟體提交程式碼,當這些改動被作者合併的時候真的滿開心的。 當中有一些滿理性的討論,受到鼓勵。 同時也有收到一些用詞比較直接的反對意見,認為應該撒回這些改動。 對於第一次參與、提交程式碼,我可能把其他人說的話看得太重,所以情緒受到滿大的影響。 但也還是有一些使用者回饋說這些改動對於他在使用螢幕閱讀器的體驗有改善不少,在小站上也有收到一些鼓勵,才能繼續堅持下去,也才能有這次的成果。

參考資料

跳過參考資料

文章互動

在Mastodon上互動