iT邦幫忙

2021 iThome 鐵人賽

DAY 4
1
Modern Web

React 從 0.5 到 1系列 第 4

[鐵人賽 Day04] 如何提升你的 React 網站易用性?(Web Accessibility)(下)- Mouse and pointer events、Development Tools

  • 分享至 

  • xImage
  •  

文章大綱與涵蓋範圍

繼上篇介紹完無障礙網站(Web Accessibility,又稱為 a11y)的目的與實踐方向,中、下篇將著重在 React Advanced Guide 裡提供的 Accessibility 指南。

在可以廣泛運用的 Accessibility 實作知識上,hightlight React 對此的支援(例如 JSX 是否也能直接應用某些 HTML 屬性?)或者調整(某些屬性在 React 裡,可能有寫法的差異)。

下篇會使用一個案例,介紹滑鼠點擊事件的實作,並且使用 React 生態系中的測試工具測試效果。

實作 Mouse and pointer events 的 Accessibility 優化

請想像一個需求:在畫面上,有三個按鈕,第一個按鈕點擊之後,會 pop up 出一個子目錄列表,這個列表需要可以關掉,第二三個按鈕點擊之後,會跳出 alert 視窗(但在這個案例我們不用關注二跟三)。

你會怎麼設計這個元件呢?以下是一個很直觀,但其實對於鍵盤使用者不太友善的做法,你是否也看出端倪了呢?原本的 React 文件使用 class component,這裡我用 hook 稍加改寫。

首先,讓我們把元件上的按鈕先畫出來,並且設定好列表 pop up 的狀態,再加上點擊按鈕之後會展開列表的函式。

export const ClickExample = () => {
  const [isShowOption, setIsShowOption] = useState(false)
	const onClickHandler = () => {
    setIsShowOption(true)
  }
  return (
    <>
      <div>
        <button onClick={onClickHandler}>Select an option</button>
        {isShowOption && (
          <ul>
            <li>Option 1</li>
            <li>Option 2</li>
            <li>Option 3</li>
          </ul>
        )}
      </div>
      <button>Another button</button>
      <button>The other button</button>
    </>
  )
}

加入了一些排版之後,此時的畫面看起來:

pic

接下來,我們要加入一個點擊空白處,就可以把列表關起來的方法。在這裡新增了一個 ref ,並指向底下的子目錄列表外層元素,讓我們可以獲得 current 的狀態。當點擊範圍不在列表元素的 current 範圍裡的時候,就收合列表。

export const ClickExample = () => {
  //..
  const toggleContainer = useRef(null);
  useEffect(() => {
    const onClickOutsideHandler = (event) => {
      if (isShowOption && !toggleContainer.current.contains(event.target)) {
        setIsShowOption(false);
      }
    }
    window.addEventListener('click', onClickOutsideHandler);
    return () => {
      window.removeEventListener('click', onClickOutsideHandler);
    };
  });
  return (
    <Container>
      <div ref={toggleContainer}>
 //..
)}

此時的畫面看起來:
pic-2

用滑鼠控制的情況下,還算順利。然而當使用者用鍵盤時,就會遇到問題。(以下的畫面鍵盤順序為:使用 tab 切換到第一個按鈕,按下 enter 打開子目錄,接下來按 enter 或是 tab 都無法把子目錄關上)。

clickEvent-3.mov

此時,可以利用別的 event handlers 事件來改善這個情境,拿掉點擊空白處關閉列表的設定。可以設計成偵測使用者的滑鼠、Focus 的狀態,如果已經離開了按鈕一一段時間,就自動關上列表。如此一來,不管是鍵盤或是滑鼠的使用者,可以順暢的操作畫面。

所以在這裡把原本的 ref 以及 event listener 拿掉,偵測按鈕,當別的按鈕被 focus 而按鈕一的 focus 狀態解除時,就把子目錄列表關上。這裏使用 setTimeout 的原因是:blur event 會比新的 focus event 更早觸發,而我們必須要先去確認別的按鈕是否被 focus 才能決定是否要關上列表。

export const ClickExample = () => {
  //..
  let timeOut
  const onBlurHandler = () => {
    timeOut = setTimeout(() => {
      setIsShowOption(false);
    })
  }
  const onFocusHandler = () => {
    clearTimeout(timeOut);
  }

  return (
		// React assists us by bubbling the blur and focus events to the parent.
    <Container>
      <div onBlur={onBlurHandler} onFocus={onFocusHandler}>
  //..
  )

}

經過調整之後,畫面的互動看起來像是這樣:

使用滑鼠

clickEvent-4.mov

使用鍵盤

clickEvent-5.mov

JSX 的無障礙網頁 Development Tools

Crete React App 會自動裝載 eslint-plugin-jsx-a11y 這個套件(所以 Create Next App 也是有的)。

https://ithelp.ithome.com.tw/upload/images/20210919/20140045PgZeZVu6ng.png

如果你想要引入更多的 accessibility 規則提示,可以調整你的 .eslintrc 檔案。你可以到這裡 https://github.com/jsx-eslint/eslint-plugin-jsx-a11y#supported-rules 來看看它支援的規則。

加上去之後,就可以看到相關提示了!例如下圖是在說 <img> 元素必須有個 alt 屬性來說明內容。

https://ithelp.ithome.com.tw/upload/images/20210919/20140045OPPD2qds87.png

這一張則是跟表單有關的設定。

https://ithelp.ithome.com.tw/upload/images/20210919/20140045P3pJaXvZrn.png

關於這些規則,套件裡的文件也都寫得相當清楚。

https://ithelp.ithome.com.tw/upload/images/20210919/20140045tC5fhG2aV2.png

如果覺得要改善自己的專案 Accessibility 毫無頭緒,不妨安裝這個套件開始,從提示反查去了解各項規範。


上一篇
[鐵人賽 Day03] 如何提升你的 React 網站易用性?(Web Accessibility)(中)- Accessible name、Keyboard Accessibility
下一篇
[鐵人賽 Day05] React 中的 Code splitting(代碼分離)方法
系列文
React 從 0.5 到 115
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言