<sub id="gqw76"><listing id="gqw76"></listing></sub>
      <sub id="gqw76"><listing id="gqw76"></listing></sub>

    1. <form id="gqw76"><legend id="gqw76"></legend></form>
    2. 前端優秀實踐不完全指南

      本文其實應該叫,Web 用戶體驗設計提升指南。

      一個 Web 頁面,一個 APP,想讓別人用的爽,也就是所謂的良好的用戶體驗,我覺得他可能包括但不限于:

      • 急速的打開速度
      • 眼前一亮的 UI 設計
      • 酷炫的動畫效果
      • 豐富的個性化設置
      • 便捷的操作
      • 貼心的細節
      • 關注殘障人士,良好的可訪問性
      • ...

      所謂的用戶體驗設計,其實是一個比較虛的概念,是秉承著以用戶為中心的思想的一種設計手段,以用戶需求為目標而進行的設計。設計過程注重以用戶為中心,用戶體驗的概念從開發的最早期就開始進入整個流程,并貫穿始終。

      良好的用戶體驗設計,是產品每一個環節共同努力的結果。

      除去一些很難一蹴而就的,本文將就頁面展示交互細節可訪問性三個方面入手,羅列一些在實際的開發過程中,積攢的一些有益的經驗。通過本文,你將能收獲到:

      1. 了解到一些小細節是如何影響用戶體驗的
      2. 了解到如何在盡量小的開發改動下,提升頁面的用戶體驗
      3. 了解到一些優秀的交互設計細節
      4. 了解基本的無障礙功能及頁面可訪問性的含義
      5. 了解基本的提升頁面可訪問性的方法

      頁面展示

      就整個頁面的展示,頁面內容的呈現而言,有一些小細節是需要我們注意的。

      整體布局

      先來看看一些布局相關的問題。

      對于大部分 PC 端的項目,我們首先需要考慮的肯定是最外層的一層包裹。假設就是 .g-app-wrapper

      <div class="g-app-wrapper">
          <!-- 內部內容 -->
      </div>
      

      首先,對于 .g-app-wrapper,有幾點,是我們在項目開發前必須弄清楚的:

      1. 項目是全屏布局還是定寬布局?
      2. 對于全屏布局,需要適配的最小的寬度是多少?

      對于定寬布局,就比較方便了,假設定寬為 1200px,那么:

      .g-app-wrapper {
          width: 1200px;
          margin: 0 auto;
      }
      

      利用 margin: 0 auto 實現布局的水平居中。在屏幕寬度大于 1200px 時,兩側留白,當然屏幕寬度小于 1200px 時,則出現滾動條,保證內部內容不亂。

      對于現代布局,更多的是全屏布局。其實現在也更提倡這種布局,即使用可隨用戶設備的尺寸和能力而變化的自適應布局。

      通常而言是左右兩欄,左側定寬,右側自適應剩余寬度,當然,會有一個最小的寬度。那么,它的布局應該是這樣:

      <div class="g-app-wrapper">
          <div class="g-sidebar"></div>
          <div class="g-main"></div>
      </div>
      
      .g-app-wrapper {
          display: flex;
          min-width: 1200px;
      }
      .g-sidebar {
          flex-basis: 250px;
          margin-right: 10px;
      }
      .g-main {
          flex-grow: 1;
      }
      

      利用了 flex 布局下的 flex-grow: 1,讓 .main 進行伸縮,占滿剩余空間,利用 min-width 保證了整個容器的最小寬度。

      當然,這是最基本的自適應布局。對于現代布局,我們應該盡可能的考慮更多的場景。做到:

      下面一種情形也是非常常見的一個情景。

      頁面存在一個 footer 頁腳部分,如果整個頁面的內容高度小于視窗的高度,則 footer 固定在視窗底部,如果整個頁面的內容高度大于視窗的高度,則 footer 正常流排布(也就是需要滾動到底部才能看到 footer)。

      看看效果:

      嗯,這個需求如果能夠使用 flex 的話,使用 justify-content: space-between 可以很好的解決,同理使用 margin-top: auto 也非常容易完成:

      <div class="g-container">
          <div class="g-real-box">
              ...
          </div>
          <div class="g-footer"></div>
      </div>
      
      .g-container {
          height: 100vh;
          display: flex;
          flex-direction: column;
      }
      
      .g-footer {
          margin-top: auto;
          flex-shrink: 0;
          height: 30px;
          background: deeppink;
      }
      

      Codepen Demo -- sticky footer by flex margin auto

      當然,實現它的方法有很多,這里僅給出一種推薦的解法。

      處理動態內容 - 文本超長

      對于所有接收后端接口字段的文本展示類的界面。都需要考慮全面(防御性編程:所有的外部數據都是不可信的),正常情況如下,是沒有問題的。

      image

      但是我們是否考慮到了文本會超長?超長了會折行還是換行?

      image

      對于單行文本,使用單行省略:

      {
          width: 200px;
          white-space: nowrap;
          overflow: hidden;
          text-overflow: ellipsis;
      }
      

      image

      當然,目前對于多行文本的超長省略,兼容性也已經非常好了:

      {
          width: 200px;
          overflow : hidden;
          text-overflow: ellipsis;
          display: -webkit-box;
          -webkit-line-clamp: 2;
          -webkit-box-orient: vertical;
      }
      

      image

      處理動態內容 - 保護邊界

      對于一些動態內容,我們經常使用 min/max-widthmin/max-height 對容器的高寬限度進行合理的控制。

      在使用它們的時候,也有一些細節需要考慮到。

      譬如經常會使用 min-width 控制按鈕的最小寬度:

      .btn {
          ...
          min-width: 120px;
      }
      

      image

      當內容比較少的時候是沒問題的,但是當內容比較長,就容易出現問題。使用了 min-width 卻沒考慮到按鈕的過長的情況:

      image

      這里就需要配合 padding 一起:

      .btn {
          ...
          min-width: 88px;
          padding: 0 16px
      }
      

      借用Min and Max Width/Height in CSS中一張非常好的圖,作為釋義:

      min-width-2

      0 內容展示

      這個也是一個常常被忽略的地方。

      頁面經常會有列表搜索,列表展示。那么,既然存在有數據的正常情況,當然也會存在搜索不到結果或者列表無內容可展示的情形。

      對于這種情況,一定要注意 0 結果頁面的設計,同時也要知道,這也是引導用戶的好地方。對于 0 結果頁面,分清楚:

      • 數據為空:其中又可能包括了用戶無權限、搜索無結果、篩選無結果、頁面無數據
      • 異常狀態:其中又可能包括了網絡異常、服務器異常、加載失敗等待

      不同的情況可能對應不同的 0 結果頁面,附帶不同的操作引導。

      譬如網絡異常:

      image

      或者確實是 0 結果:

      image

      關于 0 結果頁面設計,可以詳細看看這篇文章:如何設計產品的空白頁面?

      小小總結一下,上述比較長的篇幅一直都在闡述一個道理,開發時,不能僅僅關注正常現象,要多考慮各種異常情況,思考全面。做好各種可能情況的處理

      圖片相關

      圖片在我們的業務中應該是非常的常見了。有一些小細節是需要注意的。

      給圖片同時設置高寬

      有的時候和產品、設計會商定,只能使用固定尺寸大小的圖片,我們的布局可能是這樣:

      image

      對應的布局:

      <ul class="g-container">
          <li>
              <img src="http://placehold.it/150x100">
              <p>圖片描述</p>
          </li>
      </ul>
      
      ul li img {
          width: 150px;
      }
      

      當然,萬一假設后端接口出現一張非正常大小的圖片,上述不加保護的布局就會出問題:

      image

      所以對于圖片,我們總是建議同時寫上高和寬,避免因為圖片尺寸錯誤帶來的布局問題:

      ul li img {
          width: 150px;
          height: 100px;
      }
      

      同時,給 <img> 標簽同時寫上高寬,可以在圖片未加載之前提前占住位置,避免圖片從未加載狀態到渲染完成狀態高寬變化引起的重排問題。

      object-fit

      當然,限制高寬也會出現問題,譬如圖片被拉伸了,非常的難看:

      image

      這個時候,我們可以借助 object-fit,它能夠指定可替換元素的內容(也就是圖片)該如何適應它的父容器的高寬。

      ul li img {
          width: 150px;
          height: 100px;
          object-fit: cover;
      }
      

      利用 object-fit: cover,使圖片內容在保持其寬高比的同時填充元素的整個內容框。

      image

      object-fit 還有一個配套屬性 object-position,它可以控制圖片在其內容框中的位置。(類似于 background-position),m默認是 object-position: 50% 50%,如果你不希望圖片居中展示,可以使用它去改變圖片實際展示的 position 。

      ul li img {
          width: 150px;
          height: 100px;
          object-fit: cover;
          object-position: 50% 100%;
      }
      

      image

      像是這樣,object-position: 100% 50% 指明從底部開始展示圖片。這里有一個很好的 Demo 可以幫助你理解 object-position

      CodePen Demo -- Object position

      考慮屏幕 dpr -- 響應式圖片

      正常情況下,圖片的展示應該沒有什么問題了。但是對于有圖片可展示的情況下,我們還可以做的更好。

      在移動端或者一些高清的 PC 屏幕(蘋果的 MAC Book),屏幕的 dpr 可能大于 1。這種時候,我們可能還需要考慮利用多倍圖去適配不同 dpr 的屏幕。

      正好,<img> 標簽是有提供相應的屬性 srcset 讓我們進行操作的。

      <img src='photo@1x.png'
         srcset='photo@1x.png 1x,
                 photo@2x.png 2x,
                 photo@3x.png 3x' 
      />
      

      當然,這是比較舊的寫法,srcset 新增了新的 w 寬度描述符,需要配合 sizes 一起使用,所以更好的寫法是:

      <img 
              src = "photo.png" 
              sizes = “(min-width: 600px) 600px, 300px" 
              srcset = “photo@1x.png 300w,
                             photo@2x.png 600w,
                             photo@3x.png 1200w,
      >
      

      利用 srcset,我們可以給不同 dpr 的屏幕,提供最適合的圖片。

      上述出現了一些概念,dpr,srcset 屬性,不太了解的可以移步 前端基礎知識概述

      圖片丟失

      好了,當圖片鏈接沒問題時,已經處理好了。接下來還需要考慮,當圖片鏈接掛了,應該如何處理。

      處理的方式有很多種。最好的處理方式,是我最近在張鑫旭老師的這篇文章中 -- 圖片加載失敗后CSS樣式處理最佳實踐 看到的。這里簡單講下:

      1. 利用圖片加載失敗,觸發 <img> 元素的 onerror 事件,給加載失敗的 <img> 元素新增一個樣式類
      2. 利用新增的樣式類,配合 <img> 元素的偽元素,展示默認兜底圖的同時,還能一起展示 <img> 元素的 alt 信息
      <img src="test.png" alt="圖片描述" onerror="this.classList.add('error');">
      
      img.error {
          position: relative;
          display: inline-block;
      }
      
      img.error::before {
          content: "";
          /** 定位代碼 **/
          background: url(error-default.png);
      }
      
      img.error::after {
          content: attr(alt);
          /** 定位代碼 **/
      }
      

      我們利用偽元素 before ,加載默認錯誤兜底圖,利用偽元素 after,展示圖片的 alt 信息:

      image

      OK,到此,完整的對圖片的處理就算完成了,完整的 Demo 你可以戳這里看看:

      CodePen Demo -- 圖片處理

      交互設計優化

      接下來一個大環節是關于一些交互的細節。對于交互設計,一些比較通用的準則:

      • Don’t make me think
      • 符合用戶的習慣與預期
      • 操作便利
      • 做適當的提醒
      • 不強迫用戶

      過渡與動畫

      在我們的交互過程中,適當的增加過渡與動畫,能夠很好的讓用戶感知到頁面的變化

      譬如我們頁面上隨處可見 loading 效果,其實就是這樣一種作用,讓用戶感知頁面正在加載,或者正在處理某些事務。

      滾動優化

      滾動也是操作網頁中非常重要的一環。看看有哪些可以優化的點:

      滾動平滑:使用 scroll-behavior: smooth 讓滾動絲滑

      使用 scroll-behavior: smooth,可以讓滾動框實現平穩的滾動,而不是突兀的跳動。看看效果,假設如下結構:

      <div class="g-container">
        <nav>
          <a href="#1">1</a>
          <a href="#2">2</a>
          <a href="#3">3</a>
        </nav>
        <div class="scrolling-box">
          <section id="1">First section</section>
          <section id="2">Second section</section>
          <section id="3">Third section</section>
        </div>
      </div>
      

      不使用 scroll-behavior: smooth,是突兀的跳動切換:

      scrol

      給可滾動容器添加 scroll-behavior: smooth,實現平滑滾動:

      {
          scroll-behavior: smooth;
      }
      

      scroll2

      使用 scroll-snap-type 優化滾動效果

      sroll-snap-type 可能算得上是新的滾動規范里面最核心的一個屬性樣式。

      scroll-snap-type:屬性定義在滾動容器中的一個臨時點(snap point)如何被嚴格的執行。

      光看定義有點難理解,簡單而言,這個屬性規定了一個容器是否對內部滾動動作進行捕捉,并且規定了如何去處理滾動結束狀態。讓滾動操作結束后,元素停止在適合的位置。

      看個簡單示例:

      當然,scroll-snap-type 用法非常多,可控制優化的點很多,限于篇幅無法一一展開,具體更詳細的用法可以看看我的另外一篇文章 -- 使用 sroll-snap-type 優化滾動

      控制滾動層級,避免頁面大量重排

      這個優化可能稍微有一點難理解。需要了解 CSS 渲染優化的相關知識。

      先說結論,控制滾動層級的意思是盡量讓需要進行 CSS 動畫(可以是元素的動畫,也可以是容器的滾動)的元素的 z-index 保持在頁面最上方,避免瀏覽器創建不必要的圖形層(GraphicsLayer),能夠很好的提升渲染性能

      這一點怎么理解呢,一個元素觸發創建一個 Graphics Layer 層的其中一個因素是:

      • 元素有一個 z-index 較低且包含一個復合層的兄弟元素

      根據上述這點,我們對滾動性能進行優化的時候,需要注意兩點:

      1. 通過生成獨立的 GraphicsLayer,利用 GPU 加速,提升滾動的性能
      2. 如果本身滾動沒有性能問題,不需要獨立的 GraphicsLayer,也要注意滾動容器的層級,避免因為層級過高而被其他創建了 GraphicsLayer 的元素合并,被動的生成一個 Graphics Layer ,影響頁面整體的渲染性能

      如果你對這點還有點懵,可以看看這篇文章 -- 你所不知道的 CSS 動畫技巧與細節

      點擊交互優化

      在用戶點擊交互方面,也有一些有意思的小細節。

      優化手勢 -- 不同場景應用不同 cursor

      對于不同的內容,最好給與不同的 cursor 樣式,CSS 原生提供非常多種常用的手勢。

      在不同的場景使用不同的鼠標手勢,符合用戶的習慣與預期,可以很好的提升用戶的交互體驗。

      首先對于按鈕,就至少會有 3 種不同的 cursor,分別是可點擊,不可點擊,等待中:

      {
          cursor: pointer;    // 可點擊
          cursor: not-allowed;    // 不可點擊
          cursor: wait;    // loading
      }
      

      image

      除此之外,還有一些常見的,對于一些可輸入的 Input 框,使用 cursor: text,對于提示 Tips 類使用 cursor: help,放大縮小圖片 zoom-inzoom-out 等等:

      image

      一些常用的簡單列一列:

      • 按鈕可點擊: cursor: pointer
      • 按鈕禁止點擊:cursor: not-allowed
      • 等待 Loading 狀態:cursor: wait
      • 輸入框:cursor: text;
      • 圖片查看器可放大可縮小:cursor: zoom-in/ zoom-out
      • 提示:cursor: help;

      當然,實際 cursor 還支持非常多種,可以在 MDN 或者下面這個 CodePen Demo 中查看這里看完整的列表:

      CodePen Demo -- Cursor Demo

      點擊區域優化 -- 偽元素擴大點擊區域

      按鈕是我們網頁設計中十分重要的一環,而按鈕的設計也與用戶體驗息息相關。

      考慮這樣一個場景,在搖晃的車廂上或者是單手操作著屏幕,有的時候一個按鈕,死活也點不到。

      讓用戶更容易的點擊到按鈕無疑能很好的增加用戶體驗及可提升頁面的訪問性,尤其是在移動端,按鈕通常都很小,但是受限于設計稿或者整體 UI 風格,我們不能直接去改變按鈕元素的高寬。

      那么這個時候有什么辦法在不改變按鈕原本大小的情況下去增加他的點擊熱區呢?

      這里,偽元素也是可以代表其宿主元素來響應的鼠標交互事件的。借助偽元素可以輕松幫我們實現,我們可以這樣寫:

      .btn::before{
        content:"";
        position:absolute;
        top:-10px;
        right:-10px;
        bottom:-10px;
        left:-10px;
      }
      

      當然,在 PC 端下這樣子看起來有點奇怪,但是合理的用在點擊區域較小的移動端則能取到十分好的效果,效果如下:

      608782-20160527112625428-906375003

      在按鈕的偽元素沒有其它用途的時候,這個方法確實是個很好的提升用戶體驗的點。

      快速選擇優化 -- user-select: all

      操作系統或者瀏覽器通常會提供一些快速選取文本的功能,看看下面的示意圖:

      layout3

      快速單擊兩次,可以選中單個單詞,快速單擊三次,可以選中一整行內容。但是如果有的時候我們的核心內容,被分隔符分割,或者潛藏在一整行中的一部分,這個時候選取起來就比較麻煩。

      利用 user-select: all,可以將需要一次選中的內容進行包裹,用戶只需要點擊一次,就可以選中該段信息:

      .g-select-all {
          user-select: all
      }
      

      給需要一次選中的信息,加上這個樣式后的效果,這個細節作用在一些需要復制粘貼的場景,非常好用:

      layout4

      CodePen -- user-select: all 示例

      選中樣式優化 -- ::selection

      當然,如果你想更進一步,CSS 還有提供一個 ::selection 偽類,可以控制選中的文本的樣式(只能控制color, background, text-shadow),進一步加深效果。

      layout5

      CodePen -- user-select: all && ::selection 控制選中樣式

      添加禁止選擇 -- user-select: none

      有快速選擇,也就會有它的對立面 -- 禁止選擇。

      對于一些可能頻繁操作的按鈕,可能出現如下尷尬的場景:

      • 文本按鈕的快速點擊,觸發了瀏覽器的雙擊快速選擇,導致文本被選中:

      btn-click

      • 翻頁按鈕的快速點擊,觸發了瀏覽器的雙擊快速選擇:

      對于這種場景,我們需要把不可被選中元素設置為不可被選中,利用 CSS 可以快速的實現這一點:

      {
          -webkit-user-select: none; /* Safari */
          -ms-user-select: none; /* IE 10 and IE 11 */
          user-select: none; /* Standard syntax */
      }
      

      這樣,無論點擊的頻率多快,都不會出現尷尬的內容選中:

      btn-click-unselect

      跳轉優化

      現階段,單頁應用(Single Page Application)的應用非常廣泛,Vue 、React 等框架大行其道。但是一些常見的寫法,也容易衍生一些小問題。

      譬如,點擊按鈕、文本進行路由跳轉。譬如,經常會出現這種代碼:

      <template>
          ...
          <button @click="gotoDetail">
              Detail
          </button>
          ...
      <template>
      ...
      gotoDetail() {
          this.$router.push({
            name: 'xxxxx',
          });
      }
      

      大致邏輯就是給按鈕添加一個事件,點擊之后,跳轉到另外一個路由。當然,本身這個功能是沒有任何問題的,但是沒有考慮到用戶實際使用的場景。

      實際使用的時候,由于是一個頁面跳轉,很多時候,用戶希望能夠保留當前頁面的內容,同時打開一個新的窗口,這個時候,他會嘗試下的鼠標右鍵,選擇在新標簽頁中打開頁面,遺憾的是,上述的寫法是不支持鼠標右鍵打開新頁面的。

      原因在于瀏覽器是通過讀取 <a> 標簽的 href 屬性,來展示類似在新標簽頁中打開頁面這種選項,對于上述的寫法,瀏覽器是無法識別它是一個可以跳轉的鏈接。簡單的示意圖如下:

      image

      所以,對于所有路由跳轉按鈕,建議都使用 <a> 標簽,并且內置 href 屬性,填寫跳轉的路由地址。實際渲染出來的 DOM 可能是需要類似這樣:

      <a href="/xx/detail">Detail</a>
      

      易用性

      易用性也是交互設計中需要考慮的一個非常重要的環節,能做的有非常多。簡單的羅列一下:

      • 注意界面元素的一致性,降低用戶學習成本
      • 延續用戶日常的使用習慣,而不是重新創造
      • 給下拉框增加一些預設值,降低用戶填寫成本
      • 同類的操作合并在一起,降低用戶的認知成本
      • 任何操作之后都要給出反饋,讓用戶知道操作已經生效

      先探索,后表態

      這一點非常的有意思,什么叫先探索后表態呢?就是我們不要一上來就強迫用戶去做一些事情,譬如登錄。

      想一想一些常用網站的例子:

      • 類似虎牙、Bilibili 等視頻網站,可以先觀看體驗,一定觀看時間后才會要求登錄(登錄享受藍光)
      • 電商網站,只有到付款的時候,才需要登錄

      上述易用性先探索,后表態的內容,部分來源于:Learn From What Leading Companies A/B Test,可以好好讀一讀。

      字體優化

      字體的選擇與使用其實是非常有講究的。

      如果網站沒有強制必須使用某些字體。最新的規范建議我們更多的去使用系統默認字體。也就是 CSS Fonts Module Level 4 -- Generic font families 中新增的 font-family: system-ui 關鍵字。

      font-family: system-ui 能夠自動選擇本操作系統下的默認系統字體。

      默認使用特定操作系統的系統字體可以提高性能,因為瀏覽器或者 webview 不必去下載任何字體文件,而是使用已有的字體文件。 font-family: system-ui 字體設置的優勢之處在于它與當前操作系統使用的字體相匹配,對于文本內容而言,它可以得到最恰當的展示。

      舉兩個例子,天貓的字體定義與 Github 的字體定義:

      • 天貓font-family: "PingFang SC",miui,system-ui,-apple-system,BlinkMacSystemFont,Helvetica Neue,Helvetica,sans-serif;
      • Githubfont-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol;

      簡單而言,它們總體遵循了這樣一個基本原則:

      1、盡量使用系統默認字體

      使用系統默認字體的主要原因是性能,并且系統字體的優點在于它與當前操作系統使用的相匹配,因此它的文本展示必然也是一個讓人舒適展示效果。

      2、兼顧中西,西文在前,中文在后

      中文或者西文(英文)都要考慮到。由于大部分中文字體也是帶有英文部分的,但是英文部分又不怎么好看,但是英文字體中大多不包含中文。通常會先進行英文字體的聲明,選擇最優的英文字體,這樣不會影響到中文字體的選擇,中文字體聲明則緊隨其次。

      3、兼顧多操作系統

      選擇字體的時候要考慮多操作系統。例如 MAC OS 下的很多中文字體在 Windows 都沒有預裝,為了保證 MAC 用戶的體驗,在定義中文字體的時候,先定義 MAC 用戶的中文字體,再定義 Windows 用戶的中文字體;

      4、兼顧舊操作系統,以字體族系列 serif 和 sans-serif 結尾

      當使用一些非常新的字體時,要考慮向下兼容,兼顧到一些極舊的操作系統,使用字體族系列 serif 和 sans-serif 結尾總歸是不錯的選擇。

      對于上述的一些字體可能會有些懵,譬如 -apple-system, BlinkMacSystemFont,這是因為不同瀏覽器廠商對規范的實現有所不同,對于字體定義更多的相關細節,可以再看看這篇文章 -- Web 字體 font-family 再探秘

      可訪問性(A11Y)

      可訪問性,在我們的網站中,屬于非常重要的一環,但是大部分前端(其實應該是設計、前端、產品)同學都會忽視它。

      我潛伏在一個叫無障礙設計小組的群里,其中包含了很多無障礙設計師以及患有一定程度視覺、聽力、行動障礙的用戶,他們在群里經常會表達出一個觀點,就是國內的大部分 Web 網站及 APP 基本沒有考慮過殘障人士的使用(或者可訪問性做的非常差),非常的令人揪心。

      尤其在我們一些重交互、重邏輯的網站中,我們需要考慮用戶的使用習慣、使用場景,從高可訪問性的角度考慮,譬如假設用戶沒有鼠標,僅僅使用鍵盤,能否順暢的使用我們的網站?

      假設用戶沒有鼠標,這個真不一定是針對殘障人士,很多情況下,用戶拿鼠標的手可能在干其他事情,比如在吃東西,又或者在 TO B 類的業務,如超市收銀、倉庫收貨,很可能用戶拿鼠標的手操作著其他設備(掃碼槍)等等。

      本文不會專門闡述無障礙設計的方方面面,只是從一些我覺得前端工程師需要關注的,并且僅需要花費少量代價就能做好的一些無障礙設計細節。記住,無障礙設計對所有人都更友善

      色彩對比度

      顏色,也是我們天天需要打交道的屬性。對于大部分視覺正常的用戶,可能對頁面的顏色敏感度還沒那么高。但是對于一小部分色弱、色盲用戶,他們對于網站的顏色會更加敏感,不好的設計會給他們訪問網站帶來極大的不便。

      什么是色彩對比度

      是否曾關心過頁面內容的展示,使用的顏色是否恰當?色弱、色盲用戶能否正常看清內容?良好的色彩使用,在任何時候都是有益的,而且不僅僅局限于對于色弱、色盲用戶。在戶外用手機、陽光很強看不清,符合無障礙標準的高清晰度、高對比度文字就更容易閱讀。

      這里就有一個概念 -- 顏色對比度,簡單地說,描述就是兩種顏色在亮度(Brightness)上的差別。運用到我們的頁面上,大多數的情況就是背景色(background-color)與內容顏色(color)的對比差異。

      最權威的互聯網無障礙規范 —— WCAG AA規范規定,所有重要內容的色彩對比度需要達到 4.5:1 或以上(字號大于18號時達到 3:1 或以上),才算擁有較好的可讀性。

      借用一張圖 -- 知乎 -- 助你輕松做好無障礙的15個UI設計工具推薦

      很明顯,上述最后一個例子,文字已經非常的不清晰了,正常用戶都已經很難看得清了。

      檢查色彩對比度的工具

      Chrome 瀏覽器從很早開始,就已經支持檢查元素的色彩對比度了。以我當前正在寫作的頁面為例子,Github Issues 編輯頁面的兩個按鈕:

      image

      審查元素,分別可以看到兩個按鈕的色彩對比度:

      image

      可以看到,綠底白字按鈕的色彩對比度是沒有達到標準的,也被用黃色的嘆號標識了出來。

      除此之外,在審查元素的 Style 界面的取色器,改變顏色,也能直觀的看到當前的色彩對比度:

      image

      焦點響應

      類似百度、谷歌的首頁,進入頁面后會默認讓輸入框獲得焦點:

      image

      并非所有的有輸入框的頁面,都需要進入頁面后進行聚焦,但是焦點能夠讓用戶非常明確的知道,當前自己在哪,需要做些什么。尤其是對于無法操作鼠標的用戶。

      頁面上可以聚焦的元素,稱為可聚焦元素,獲得焦點的元素,則會觸發該元素的 focus 事件,對應的,也就會觸發該元素的 :focus 偽類。

      瀏覽器通常會使用元素的 :focus 偽類,給元素添加一層邊框,告訴用戶,當前的獲焦元素在哪里。

      我們可以通過鍵盤的 Tab 鍵,進行焦點的切換,而獲焦元素則可以通過元素的 :focus 偽類的樣式,告訴用戶當前焦點位置。

      當然,除了 Tab 鍵之外,對于一些多輸入框、選擇框的表單頁面,我們也應該想著如何簡化用戶的操作,譬如用戶按回車鍵時自動前進到下一字段。一般而言,用戶必須執行的觸按越少,體驗越佳。??

      下面的截圖,完全由鍵盤操作完成

      a11y

      通過元素的 :focus 偽類以及鍵盤 Tab 鍵切換焦點,用戶可以非常順暢的在脫離鼠標的情況下,對頁面的焦點切換及操作。

      然而,在許多 reset.css 中,經常能看到這樣一句 CSS 樣式代碼,為了樣式的統一,消除了可聚焦元素的 :focus 偽類:

      :focus {
          outline: 0;
      }
      

      我們給上述操作的代碼。也加上這樣一句代碼,全程再用鍵盤操作一下

      a11y2

      除了在 input 框有光標提示,當使用 Tab 進行焦點切換到 select 或者到 button 時,由于沒有了 :focus 樣式,用戶將完全懵逼,不知道頁面的焦點現在處于何處。

      保證非鼠標用戶體驗,合理運用 :focus-visible

      當然,造成上述結果很重要的一個原因在于。:focus 偽類不論用戶在使用鼠標還是使用鍵盤,只要元素獲焦,就會觸發。

      而其本身的默認樣式又不太能被產品或者設計接受,導致了很多人會在焦點元素觸發 :focus 偽類時,通過改變 border 的顏色或者其他一些方式替代或者直接禁用。而這樣做,從可訪問性的角度來看,對于非鼠標用戶,無疑是災難性的。

      基于此,在W3 CSS selectors-4 規范 中,新增了一個非常有意思的 :focus-visible 偽類。

      :focus-visible:這個選擇器可以有效地根據用戶的輸入方式(鼠標 vs 鍵盤)展示不同形式的焦點。

      有了這個偽類,就可以做到,當用戶使用鼠標操作可聚焦元素時,不展示 :focus 樣式或者讓其表現較弱,而當用戶使用鍵盤操作焦點時,利用 :focus-visible,讓可獲焦元素獲得一個較強的表現樣式。

      看個簡單的 Demo:

      <button>Test 1</button>
      
      button:active {
        background: #eee;
      }
      button:focus {
        outline: 2px solid red;
      }
      

      使用鼠標點擊:

      a11y3

      可以看到,使用鼠標點擊的時候,觸發了元素的 :active 偽類,也觸發了 :focus偽類,不太美觀。但是如果設置了 outline: none 又會使鍵盤用戶的體驗非常糟糕。嘗試使用 :focus-visible 偽類改造一下:

      button:active {
        background: #eee;
      }
      button:focus {
        outline: 2px solid red;
      }
      button:focus:not(:focus-visible) {
        outline: none;
      }
      

      看看效果,分別是在鼠標點擊 Button 和使用鍵盤控制焦點點擊 Button:

      a11y4

      CodePen Demo -- :focus-visible example

      可以看到,使用鼠標點擊,不會觸發 :foucs,只有當鍵盤操作聚焦元素,使用 Tab 切換焦點時,outline: 2px solid red 這段代碼才會生效。

      這樣,我們就既保證了正常用戶的點擊體驗,也保證了一批無法使用鼠標的用戶的焦點管理體驗。

      值得注意的是,有同學會疑惑,這里為什么使用了 :not 這么繞的寫法而不是直接這樣寫呢:

      button:focus {
        outline: unset;
      }
      button:focus-visible {
        outline: 2px solid red;
      }
      

      為的是兼容不支持 :focus-visible 的瀏覽器,當 :focus-visible 不兼容時,還是需要有 :focus 偽類的存在。

      使用 WAI-ARIA 規范增強語義 -- div 等非可獲焦元素模擬獲焦元素

      還有一個非常需要注意的點。

      現在很多前端同學在前端開發的過程中,喜歡使用非可獲焦元素模擬獲焦元素,譬如:

      • 使用 div 模擬 button 元素
      • 使用 ul 模擬下拉列表 select 等等

      當下很多組件庫都是這樣做的,譬如 element-ui 和 ant-design。

      在使用非可獲焦元素模擬獲焦元素的時候,一定要注意,不僅僅只是外觀長得像就完事了,其行為表現也需要符合原本的 buttonselect 等可聚焦元素的性質,能夠體現元素的語義,能夠被聚焦,能夠通過 Tab 切換等等。

      基于大量類似的場景,有了 WAI-ARIA 標準,WAI-ARIA是一個為殘疾人士等提供無障礙訪問動態、可交互Web內容的技術規范。

      簡單來說,它提供了一些屬性,增強標簽的語義及行為:

      • 可以使用 tabindex 屬性控制元素是否可以聚焦,以及它是否/在何處參與順序鍵盤導航
      • 可以使用 role 屬性,來標識元素的語義及作用,譬如使用 <div id="saveChanges" tabindex="0" role="button">Save</div> 來模擬一個按鈕
      • 還有大量的 aria-* 屬性,表示元素的屬性或狀態,幫助我們進一步地識別以及實現元素的語義化,優化無障礙體驗

      使用工具查看標簽的語義

      我們來看看 Github 頁面是如何定義一個按鈕的,以 Github Issues 頁面的 Edit 按鈕為例子:

      image

      這一塊,清晰的描述了這個按鈕在可訪問性相關的一些特性,譬如 Contrast 色彩對比度,按鈕的描述,也就是 Name,是給屏幕閱讀器看到的,Role 標識是這個元素的屬性,它是一個按鈕,Keyboard focusable 則表明他能否被鍵盤的 Tab 按鈕給捕獲。

      分析使用非可聚焦元素模擬的按鈕

      這里,我隨便選取了我們業務中一個使用 span 模擬按鈕的場景,是一個面包屑導航,點擊可進行跳轉,發現慘不忍睹:

      image

      HTML 代碼:

      <span class="ssc-breadcrumb-item-link"> Inbound </span>
      

      image

      基本上可訪問性為 0,作為一個按鈕,它不可被聚焦,無法被鍵盤用戶選中,沒有具體的語義,色彩對比度太低,可能視障用戶無法看清。并且,作為一個能進行頁面跳轉的按鈕,它沒有不是 a 標簽,沒有 href 屬性。

      即便對于面包屑導航,我們可以不將它改造成 <a> 標簽,也需要做到最基本的一些可訪問性改造:

      <span role="button" aria-label="goto inbound page" tabindex="0" class="ssc-breadcrumb-item-link"> Inbound </span>
      

      不要忘了再改一下顏色,達到最低色彩對比度以上,再看看:

      image

      OK,這樣,一個最最最基本的,滿足最低可訪問性需求的按鈕算是勉強達標,當然,這個按鈕可以再更進一步進行改造,涉及了更深入的可訪問性知識,本文不深入展開。

      分析組件庫的 A11Y

      最后,在我們比較常用的 Vue - element-ui、React - ant-design 中,我們來看看 ant-design 在提升可訪問性相關的一些功能。

      以 Select 選擇框組件為例,ant-design 利用了大量的 WAI-ARIA 屬性,使得用 div 模擬的下拉框不僅僅在表現上符合一個下拉框,在語義、行為上都符合一個下拉框,簡單的一個例子:

      image

      看看使用 div 模擬下拉框的 DOM 部分:

      image

      再看看在交互體驗上:

      a11y5

      上述操作全是在鍵盤下完成,看著平平無奇,實際上組件庫在正常響應可獲焦元素切換的同時,給用 div 模擬的 select 加了很多鍵盤事件的響應,可以利用回車,上下鍵等對可選項進行選擇。其實是下了很多功夫。

      對于 A11Y 相關的內容,篇幅及內容非常之多,本文無法一一展開,感興趣的可以通讀下下列文章:

      總結一下

      本文從頁面展示交互細節可訪問性三個大方面入手,羅列一些在實際的開發過程中,積攢的一些有益的經驗。雖然不夠全面,不過從一開始也就沒想著大而全,主要是一些可能有用但是容易被忽視的點,也算是一個不錯的查缺補漏小指南。

      當然,很多都是我個人的觀點想法,可能有一些理解存在一些問題,一些概念沒有解讀到位,也希望大家幫忙指出。

      最后

      本文到此結束,希望對你有幫助 ??

      更多精彩 CSS 技術文章匯總在我的 Github -- iCSS ,持續更新,歡迎點個 star 訂閱收藏。

      如果還有什么疑問或者建議,可以多多交流,原創文章,文筆有限,才疏學淺,文中若有不正之處,萬望告知。

      posted @ 2021-02-24 10:15  ChokCoco  閱讀(4882)  評論(25編輯  收藏
      最新chease0ldman老人|无码亚洲人妻下载|大香蕉在线看好吊妞视频这里有精品www|亚洲色情综合网

        <sub id="gqw76"><listing id="gqw76"></listing></sub>
        <sub id="gqw76"><listing id="gqw76"></listing></sub>

      1. <form id="gqw76"><legend id="gqw76"></legend></form>