WeHelp
優化網站accessibility之aria-live應用
2023-11-26 18:04:12
好的Accessibility網站能讓障礙者更舒服地瀏覽網頁,而障礙者分成很多種,例如聽覺障礙、視覺障礙、行動障礙等,接下來會針對視覺障礙的accessibility設定將aria-live導入網頁的通知訊息及輪播元件。 --- ## 什麼是aria-live 以不重新刷新頁面的情況下去更新動態的內容,通常為一個小區域的內容,而此內容的區域需標註為aria-live,讓使用者能在不把焦點放上此區域的情況下聽到screen reader(螢幕報讀軟體ex:voiceover, NVDA)報讀此區域更新的內容。aria-live有三個設定值,分別為 `off`, `polite`, `assertive`。 這三個設定值分別對應到screen reader的報讀優先順序。`off` 為靜音,screen reader不會報讀此區域的更新內容; `polite`為中間順序,當screen reader正在報讀其他內容時,被設定為`polite`的區域則會被安排到下一個報讀的訊息;`assertive` 為最優先的順序,將會直接插播為第一則訊息讓sceern reader報讀。 ## 通知訊息元件範例 由於通知訊息有即時性且只會顯示在網頁上幾秒鐘,所以將通知訊息的內容加上aria-live=”assertive”的設定,當有新訊息跳出,screen reader則會馬上報讀。 ```jsx <div v-if="userPopupMessage.content.length > 0" aria-live="assertive" > <p class="text-sm font-medium text-gray-700"> {{ userPopupMessage.content }} </p> </div> ``` ## 輪播元件範例 此輪播元件為自動撥放,當設定值固定為`polite`,使用者瀏覽到其他區域時,會持續穿插輪播的內容,此結果並不符合使用情境,所以將`polite`及`off`交替使用,當使用者聚焦在輪播元件區域包含上下一張及底下控制點的按鈕時,將設定值從`off`變更為`polite`,使用者點擊輪播的控制按鈕使得輪播內容更新時,screen reader就會報讀更新內容,離開輪播元件區域後,screen reader則不報讀更新內容。 以下範例使用headlessUI的tab元件實作成輪播元件 ```jsx <template> <TabGroup :selected-index="activeSlideIndex" @change="getActiveSlideIndex"> <div class="flex items-center justify-center"> <button aria-label="上一張圖片" @click="toPrev" @focus="autoSlideOff" @blur="autoSlideOn" @mouseenter="autoSlideOff" @mouseleave="autoSlideOn"> <ChevronLeftIcon class="h-6 w-6 cursor-pointer text-indigo-600" aria-controls="carousel" /> </button> <!--To put aria-live at the element which you want screen reader read it out. --> <TabPanels class="carousel-container relative" :aria-live="liveRegion"> <TabPanel v-for="item in banners" :key="item.id" @focus="autoSlideOff" @blur="autoSlideOn" @mouseenter="autoSlideOff" @mouseleave="autoSlideOn" > <a :key="item.id" tabindex="-1" :href="item.url" target="blank"> <img v-show="activeSlideIndex == banners.indexOf(item)" class="absolute h-full w-full rounded-md" :src="item.imageUrl" :alt="item.title" /> </a> </TabPanel> </TabPanels> <button aria-label="下一張圖片" @click="toNext" @focus="autoSlideOff" @blur="autoSlideOn" @mouseenter="autoSlideOff" @mouseleave="autoSlideOn"> <ChevronRightIcon class="h-6 w-6 cursor-pointer text-indigo-600" aria-controls="carousel" /> </button> </div> <TabList class="mt-5 flex justify-center space-x-5"> <Tab v-for="(dot, index) in banners" :key="dot.id" v-slot="{ selected }" as="template"> <div :aria-label="`第${index + 1}張`" aria-controls="carousel" @focus="autoSlideOff" @blur="autoSlideOn" @mouseenter="autoSlideOff" @mouseleave="autoSlideOn" ></div> </Tab> </TabList> </TabGroup> </template> <script setup> import { ChevronRightIcon, ChevronLeftIcon } from "@heroicons/vue/solid"; import { Tab, TabGroup, TabList, TabPanel, TabPanels } from "@headlessui/vue"; import { computed, ref, defineProps, onMounted } from "vue"; const liveRegion = ref("off"); let autoSlide; const autoSlideOn = () => { autoSlide = setInterval(slide, 5000); liveRegion.value = "off"; }; const autoSlideOff = () => { clearInterval(autoSlide); liveRegion.value = "polite"; }; </script> ``` ### Resource https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Live_Regions https://www.w3.org/WAI/ARIA/apg/patterns/carousel/examples/carousel-1-prev-next/